4
votes

I'm trying to implement responsive images on my website using srcset and sizes. When testing on my computer everything looks and works great. The image downloaded is the next-largest image when compared to current page width (page width of 500px would retrieve 720px wide image). Here's what I'm using:

<img src="image-240w.jpg"
    srcset="image-1140w.jpg 1140w,
        image-940w.jpg 940w,
        image-720w.jpg 720w,
        image-480w.jpg 480w,
        image-240w.jpg 240w"
    sizes="(max-width: 1140px) 100vw, 1140px">

On my phone is where I get confused. I have a Nexus 5X with a 1920x1080 resolution screen with a device pixel ratio of 2.5. With the viewport meta added to my page (<meta name="viewport" content="width=device-width, initial-scale=1">) media queries respond as expected--as if my device were just over 400px wide (1080px/4 = 432px). To support that is example A below. It is a 480px wide image which, as expected, hangs past the edge of the page by about 48px. Example B is an image that is 1140px wide which is obviously much larger than the 432px wide viewport. Example C is the result of the img tag from above (and is what I'm aiming for).

comparison

At first, I was pleased that everything worked. However, when viewing with my developer tools I can see that the img tag with srcset actually downloaded the 1140px wide image. It seems to me that the 480px wide image (which is just barely larger than the 432px wide viewport) should have been selected. Instead, the image downloaded was for that of the 1080px wide screen.

Why do media queries respond as I would expect them to (acting as if my screen were only 432px wide) but the responsive images only care about the image size that matches the real screen resolution? It must have something to do with the 2.5 device pixel ratio but I just don't get how.

My goal is that on my device I would get the 480px image, not the largest one. How do I accomplish this?

Edit

Or perhaps my desires are incorrect and the browser is doing exactly what it should be doing. Explain why, when a 480px wide image is already hanging off the edge of the screen, it should still pick the 1140px wide image.

Answer/Proof

As pointed out in the answer below, the device is doing exactly what it should be doing. Just to prove a point, here is my device (432 CSS pixels but 1080 device pixels) displaying a 480px and 1140px image. Although the 480px image matches the CSS pixels, it is terribly blurry when compared to the 1140px image that matches the device pixels. So, the device knows best and although I expected it to pick the smaller image, it knew it needed the larger image (from the responsive srcset and sizes) to present the image correctly.

480vs1140

1

1 Answers

1
votes

The answer is: Yes it has to do with the device pixel ratio. And yes, the device is doing it right.

The image is shown correctly because if you don't override the image dimension with CSS the sizes attribute is used (in your case "100vw", which is ~"100%") (If you change your sizes to "50vw" you will get around "50%" width).

The key part is that there are different concepts of pixels.

Normal media queries (min-width, max-width...) are measured in so called layout pixels (also CSS pixels). These pixels are an abstraction of the real physical pixels (device pixels) to have a satisfying and reliable pixel unit to do layout stuff (CSS) for retina screens (and sometimes very low resolution screens). Using the physical pixels as layout pixels would mean on small but high resolution devices very, very small layout objects. In CSS world a pixel means a layout pixel. This is calculated by device pixel / device pixel ration.

However, in case of images its all about how many pixels your device really has. If it has 1000px pixels screen width and the image is displayed at 100vw, it makes sense to load a 1000 pixel width image to satisfy the full quality of your screen. (= Each physical screen pixel gets a real image pixel assigned.)

This makes even sense if these 1000 physical pixels are measured in only 360 layout pixels.

See also: A pixel is not a pixel.