Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Img with srcset and sizes not loading the image I expect

Tags:

html

css

image

I'm trying to optimize a page which consists of a grid of images with breakpoints that makes it use 1, 2, 3 or 4 columns.

The html looks like this:

<img srcset=" image-300x200.jpg 300w, image-original.jpg 600w" sizes=" (min-width: 1px) calc( 100vw * (0.94 * 1.000) * 1.00 ), (min-width: 480px) calc( 100vw * (0.94 * 0.905) * 0.50 ), (min-width: 768px) calc( 100vw * (0.94 * 0.850) * 0.33 ), (min-width: 981px) calc( 100vw * (0.94 * 0.835) * 0.25 ), 280px" alt="E-Books customer service for Dutch Libraries" width="400" height="284">

The calc() functions may look a bit complicated but I've tested them with various viewport widths and then verified the size of the image in the browser and the math checks out.

For completeness, here's what it does:

[viewport width] - [94% container width] - [column gutters] / [nr of columns]

But whatever I try, Chrome (almost, yay for consistency) always selects the big image even when the size of the img on screen is well below 300px. I checked this in the developer tools > inspector > properties > img > currentsrc as pointed out in this answer

Can anyone help me?

like image 724
REJH Avatar asked Nov 28 '16 13:11

REJH


People also ask

Why is Srcset not working?

If you find yourself confused about why srcset is not working as expected. And why the browser is using the wrong image, it's probably because of “devicePixelRatio”. Once you factor that into your estimations, things will start to look right.

Does Srcset work without sizes?

You can use sizes to make srcset work even better. Without it, the browser uses the full width of the viewport when choosing an image from a srcset .

What is Srcset in IMG tag?

The srcset attribute on an <img> tag specifies multiple image resources (URLs) for the img element. Together with the sizes attribute they create responsive images that adjust according to browser conditions.

What is Srcset size?

srcset - To define multiple image sources of different widths and let the browser pick the most appropriate candidate during HTML parsing. sizes - To define the size of the image element. It could be a fixed size like 225px or relative to the viewport.


1 Answers

I think I figured it out. it seems that the media queries don't work as I expected.

For example, with these rules:

sizes=" (min-width: 1px) ... (min-width: 480px) ... (min-width: 768px) ... "

one would assume that

  • Line #1 is true when screen > 1px wide
  • Line #2 is true when screen > 480px, overriding line #1
  • Line #3 is true when screen > 768px, overriding line #1 and #2

This is not how it works, at least not in practice. I think that the browser just looks for a rule that evaluates to true and calls it a day.

So it just goes:

  • Line #1 is true! Done! Applying the rule! Easy!

When I looked at my rules and the result with this logic in mind, it suddenly made sense that the browser insisted on using the biggest image because the calc() function I use for the first line is:

calc( 100vw * (0.94 * 1.0) * 1.0 ) - which is a complicated way of writing windowWidth * 0.94.

In other words, the browser assumes that the image is always 94% of the entire width of the window and doesn't apply any of the other calculations that take the breakpoints into account.

Anyway, changing the above rules to this:

sizes=" (min-width: 1px) and (max-width: 479px) ... (min-width: 480px) and (max-width: 767px) ... (min-width: 768px) and (max-width: 980px) ... "

makes sure that the rule only applies up to a certain point. Every time the next line evaluates as true, the other lines don't.

So this is what I went with in the end:

<img src="image-fallback.jpg" srcset=" image-300x200.jpg 300w, image-480x320.jpg 480w, image-600x400.jpg 600w, image-960x640.jpg 960w, image-1200x800.jpg 1200w" sizes=" (min-width: 1px) and (max-width: 479px) calc( 100vw * (0.94 * 1.000) * 1.00 ), (min-width: 480px) and (max-width: 767px) calc( 100vw * (0.94 * 0.905) * 0.50 ), (min-width: 768px) and (max-width: 980px) calc( 100vw * (0.94 * 0.850) * 0.33 ), (min-width: 981px) and (max-width: 1088px) calc( 100vw * (0.94 * 0.835) * 0.25 ), (min-width: 1089px) calc( 1089px * (0.94 * 0.835) * 0.25 ), 280px" />

And here's a working example of the above: Image srcset example (working)

Note: once the browser has loaded a larger image, it's reluctant to load smaller ones. That's what the 'force refresh' button is for.

Note #2: For debugging I added more source images compared to my original question. I thought it would be easier to keep it simple with two sizes but I think I would have never figured this out if I hadn't added a bunch. When I only had 2 images, I thought it always chose the biggest. That isn't true, it just never chose the image I expected ;)

like image 122
REJH Avatar answered Sep 30 '22 22:09

REJH