I have following snap-points: 480px, 900px, 1800px, 2400px.
and this markup:
<img
sizes="(max-width: 2400px) 100vw, 2400px"
srcset="
boat-480.jpg 480w,
boat-900.jpg 900w,
boat-1800.jpg 1800w,
boat-2400.jpg 2400w"
src="boat-2400.jpg"
alt="This is a boat">
How should I get responsive images to work?
1. Basics
Device-pixel ratio
Device-pixel ratio is the number of device pixels per CSS pixel which is related to:
Pixel density of the device (number of physical pixels per inch)
Zoom level of the browser
So, greater Pixel density and/or higher Zoom level results in higher Device-pixel ratio.
srcset attribute & x descriptor
On <img> tag, the x descriptor in the srcset attribute is used to define the device-pixel ratio. So in:
<img src="image.jpg" srcset="image-1x.jpg 1x, image-2x.jpg 2x, image-3x.jpg 3x">
for a device-pixel ratio of 1, the image image-1x.jpg will be used.
for a device-pixel ratio of 2, the image image-2x.jpg will be used.
for a device-pixel ratio of 3, the image image-3x.jpg will be used.
for the fallback the src attribute (image.jpg) will be used.
srcset attribute & w descriptor
If you want a different image on a larger or smaller viewport, the w descriptor in srcset and a new attribute (sizes) comes into play:
<img src="image.jpg" srcset="image-1x.jpg 200w, image-2x.jpg 400w, image-3x.jpg 600w">
This mentions that the width of the first image is 200px, second image is 400px, and third image is 600px. Also, if the user’s screen is 150 CSS pixels wide, this equates to the following in terms of x descriptors:
<img src="image.jpg" srcset="image-1x.jpg 1.33x, image-2x.jpg 2.67x, image-3x.jpg 4x">
sizes attribute
The actual implementation where you’d want a different size image (different height, width) on different screen sizes is accomplished by using sizes attribute along with the w descriptor of srcset attribute.
<img src="image.jpg" sizes="50vw" srcset="image-1x.jpg 200w, image-2x.jpg 400w, image-3x.jpg 600w">
If the browser width is 500 CSS pixels, the image will be displayed 250px wide (because of 50vw). Now, this is equivalent to specifying:
<img src="image.jpg" srcset="image-1x.jpg 0.8x, image-2x.jpg 1.6x, image-3x.jpg 2.4x">
So, for a 1.5x display, image-2x.jpg will be downloaded by a browser, since it gives a device-pixel ratio of 1.6x (which is most suitable for a 1.5x display).
2. Answering your question
You have mentioned that you have emulated a 480px CSS width screen.
Because you have set sizes to 100vw, that is equivalent to specifying:
<img src="boat-2400.jpg" srcset="
boat-480.jpg 1x,
boat-900.jpg 1.88x,
boat-1800.jpg 3.75x,
boat-2400.jpg 5x">
There is chance you have 3x display, and thus the browser downloads boat-1800.jpg file.
Questions
Oddly, when I tested this on Chrome on iOS the browser actually downloaded boat-2400.jpg which is even more worrying.
That would be due to the higher Device-pixel ratio of your iOS device, which is likely to be something near 5.
Have I missed something here?
I dont think so.
I imagine I don't need the sizes attribute because I have the image set to 100vw in all views
The value of sizes is 100vw by default. But if you want to use w descriptor and want to have something other than 100vw for your sizes, you need sizes attribute.
Related
Not sure if this started happening very recently, or if this has been an issue for longer, but I feel it's the former. I think I would have noticed, otherwise.
When I add an image to my post, and set the size to 'enlarged' or 'full' (presumably, I'm translating this from Portuguese), my (custom) theme shows these images either enlarged, or in full width. (To allow for this, I added add_theme_support('align-wide') to my functions.php.)
However, the file that is used, on larger screens, is not the correct one.
This is the image tag I get when including an image that is set to have full width:
<img loading="lazy" width="1003" height="564" src="[...]image.jpg?resize=640%2C360&ssl=1" alt="" class="wp-image-115865 shadow" srcset="[...]image.jpg?w=1920&ssl=1 1920w, [...]image.jpg?resize=300%2C169&ssl=1 300w, [...]image.jpg?resize=1024%2C576&ssl=1 1024w, [...]image.jpg?resize=1536%2C864&ssl=1 1536w, [...]image.jpg?resize=640%2C360&ssl=1 640w, [...]image.jpg?resize=1320%2C743&ssl=1 1320w, [...]image.jpg?resize=150%2C84&ssl=1 150w" sizes="(max-width: 640px) 100vw, 640px">
You can see that the image is displayed at 1003x564 pixels, but that the 'sizes' attribute sets a max-width at 640 pixels.
As a result, this image, displayed at 1003x564 pixels, is an upscaled image of 640 pixels wide.
The result is pixelated, which is not pretty.
What is defining the 'sizes' attribute? Why is it, here, set to 640 pixels? Can I change this? How?
The function that adds attr in images is wp_get_attachment_image()
The function that adds size attr in images is wp_calculate_image_sizes()
They have given filter wp_calculate_image_sizes to modify as per your need.
I am adding a image to my site that will need to be different dimensions based on the resolution of the screen (pretty common).
What is tripping me up however, is the images that I have set in <img srcset="X"> are not changing at the given widths.
(quick note, I use incogento in chrome so this is not the FAMOUS cache issue)
anyway - on with the show:
Several images (specifically sized)
HTML CODE:
<img src="im2/1280.jpg"
srcset="im2/120.jpg 120w,
im2/320.jpg 320w,
im2/640.jpg 640w,
im2/1280.jpg 1280w,
im2/1920.jpg 1920w"
sizes="(max-width: 250px) 120px,
(max-width: 480px) 320px,
(max-width: 720px) 640px,
(max-width: 1400px) 1280px,
(max-width: 2000px) 1920px,
"
alt="Image description">
So based on my above code I would expect that the first image would be 120.jpg (if the screen was under 250px wide) - however:
First is 320px
at 460px it shows the image for 1280px
My guess is that I have missed some key bit of info on how this works.
if anyone can shed some light on this that would be great.
Thanks in advance -
Wally
A great article to read about this topic can be found here (its next level at explaining how the picture and srcset tag should be used)
https://alligator.io/html/picture-element/
Short answer is that images tags <img> that use srcset <img srcset="X"> will be given a width of the image for the browser to decide what to do with <img srcset="X.jpg 200w">
BUT IT IS THE BROWSER that decides what image to use based off the values given.
I.e.
<img srcset="X.jpg 1000w">
The browsers might use that on a display that is 400px wide
For specific images to be used at specific screen sizes then refer to the linked article which gives all the info required.
How does the srcset attribute determine the correct image in conjunction with the sizes attribute? Take this image for example:
<img alt="Demo image"
sizes="(min-width: 1024px) 512px,
100vw"
srcset="img/banner-large.jpg 2048w,
img/banner-medium.jpg 1400w,
img/banner-small.jpg 800w">
(I cleared the cache in Chrome)
I thought that the last image would always be chosen (800w), because of the 512px (sizes) and the image width of 800w (srcset), but that image did not always get selected? Why?
Here is a detailed guide on using Srcset with sizes.
sizes attribute contains a comma-separated list. Each item in the list describes the size of the image in relation to the viewport.
Using the sizes attribute with srcset provides the browser with enough information to start downloading the right image as soon as it sees an <img> tag in HTML without waiting for styles sheets to complete downloading and parsing.
Why do we need sizes?
If you are wondering why the browser is not aware of how big the image will render, checkout how the browser loads a web page.
The syntax:
<img src="image.jpg"
srcset="small.jpg 300w,
medium.jpg 600w,
large.jpg 900w"
sizes="(max-width: 300px) 100vw, (max-width: 600px) 50vw, (max-width: 900px) 33vw, 900px"
/>
Each comma-separated item in sizes has:
Media conditions, for example, (max-width: 300px) - It describes a possible state that the screen can be in. (max-width: 300px) means when the viewport width is 300 CSS pixels or less. It is similar to media queries but with some limitations. You cannot use screen or print.
An empty space.
The width of the image element when the media condition is true. You can provide an absolute length (px, em) or a length relative to the viewport (vw), but not percentages.
Demo - srcset with sizes
Let’s see this in action with a live demo - https://imagekitio.github.io/responsive-images-guide/srcset-sizes.html
The layout is such that:
If viewport width is above 900px, each image takes a fix 225px width.
Upto 900px, each image takes up 33vw i.e. 33% width of total viewport width.
Upto 700px, each image takes up 50vw i.e. 50% width of total viewport width.
Upto 400px, each image takes up 100vw i.e. the whole viewport width.
HTML markup of a single image element looks like this:
<img src="https://ik.imagekit.io/ikmedia/women-dress-1.jpg"
srcset="https://ik.imagekit.io/ikmedia/women-dress-1.jpg?tr=w-225 225w,
https://ik.imagekit.io/ikmedia/women-dress-1.jpg?tr=w-300 300w,
https://ik.imagekit.io/ikmedia/women-dress-1.jpg?tr=w-350 350w,
https://ik.imagekit.io/ikmedia/women-dress-1.jpg?tr=w-640 640w"
sizes="(max-width: 400px) 100vw, (max-width: 700px) 50vw, (max-width: 900px) 33vw, 225px">
Let’s see what happens at different screen size and DPR values -
The sizes attribute determines the media condition that applies to the current device width (the first media condition that applies is selected). Then, the browser checks the srcset attribute to find the image that most closely matches the slot size determined by the sizes attribute. Note that the browser chooses a larger image for high-res displays like Retina (usually chooses an image close to double the width it would choose on a "normal" resolution display). See Responsive images and Responsive images: If you're just changing resolutions, use srcset for a lot more detail on how this works.
So in your case, you would expect to get the banner-small.jpg image on a "normal" resolution device where device width is at least 1024px (and you would also expect to get that same image on smaller width "normal" resolution devices due to the larger widths of your other srcset image options).
Some reasons that you might not get the results you expect:
Older browser versions don't support srcset
Did not specify <meta name="viewport" content="width=device-width"> to force devices to adopt their real width when loading the page.
Browsers may display cached images rather than selecting the closest size match from srcset (as you noted in your question).
When attempting to display multiple sizes of the same image on a page, browsers may download only the largest image needed and use it in each instance (rather than downloading multiple images).
If you are attempting to test image selection behavior in some sort of sandboxed iframe environment like jsfiddle, it is difficult to be sure that the browser is interpreting the size of the display pane as "device width" (I have had mixed results with srcset in these types of environments). It seems to behave reasonably in a SO snippet for browsers like Chrome and Firefox (as long as you clear the cache). See below for an example snippet (better used in your own environment) that makes it visually obvious which image has been selected when testing.
<img srcset="https://via.placeholder.com/300x150 300w,
https://via.placeholder.com/600x300 600w"
sizes="(min-width: 1024px) 600px,
100vw"
src="https://via.placeholder.com/300x150"
alt="placeholder image">
I have a stock image of 1772 px. This image is the largest available. The raw file is gone so I can't create an image of 5120 px wide. How would the markup and CSS look for that image if I want to be able to stretch it nicely across the entire width of the iMac?
Minimum requirements:
I'm using Bootstrap so it has to work with that. And preferably with the img-responsive built-in class. Do I need to have the img-tag in a container-fluid div?
<picture>-element needs to be used since art directing is involved. When the viewport hits 767px and lower I'm displaying the image in portrait mode.
Here's the code I'm experimenting with:
<picture>
<source media="(min-width: 768px)"
srcset="/img/landscape/large.jpg 1772w,
/img/landscape/medium.jpg 886w,
/img/landscape/small.jpg 443w"
sizes="100w" />
<source srcset="/img/portrait/large.jpg 955w,
/img/portrait/medium.jpg 640w,
/img/portrait/small.jpg 320w"
sizes="100vw" />
<img src="/img/landscape/medium.jpg" alt="" />
</picture>
Currently firefox and Chrome managemes to strech out the image nicely but IE10 stops at 1772px and leaves white-space on the right of the image.
If I set the img to width:100% the image will stretch but I'm confused of wheather this is the right approach since in Bootstrap they use max-width.
For my mobile website I want to show images of different but known heights/widths with two constraints:
The image should take up the whole width of the browserview
The height should be scaled (down or up) accordingly to keep the proportions
As soon as the browser downloads the image, it is really easy with the following CSS:
<img src="myImageURl" style="width: 100%; height: auto;" />
But because the loading of the image takes some time, I want the browser to layout the image before it downloads it. So the browser does not need to rerender the page, once he fetches the image. I tried the following approaches, which failed:
// The image is not layouted before fetched
<img src="myImageURl" height="myImageHeight" width="myImageWidth" style="width: 100%; height: auto;" />
// The image is layouted, but wrong: height is not proportional to the width anymore
<img src="myImageURl" style="width: 100%; height: myImageHeight;" />
I would love some help here. But please in CSS, I don't want to use Javascript / jQuery if I don't have to.
UPDATE
I guess I am not the only one with this problem: https://graphicdesign.stackexchange.com/questions/3274/fluid-images-how-to-set-width-and-height
As Pete already said, you can not do any (automatic) calculations before the image is downloaded, so the browser knows its width and height.
But since you are able to determine the aspect ratio of the image beforehand, you could try a “workaround” by adding an extra placeholder element around the image – and make use of the fact that padding values given in percentage always are calculated based on the width of an element, even for padding-top/-bottom.
That could look something like this:
<div style="position:relative; width:100%; height:0; padding-top:50%;">
<img style="position:absolute; top:0; left:0; width:100%;" src="…">
</div>
This is a div element with no height, but a padding-top – that will give it an actual “height” of 50% of the computed 100% width. (That would be for an image with an aspect ratio of 2:1 – for 3:1 the padding-top value would have to be 33.333% accordingly – and so forth, basically height/width*100.)
That should span up our placeholder even before the image is loaded.
The image itself is positioned absolutely inside this relatively positioned placeholder – that makes sure it gets displayed at the same position in the document.
The only thing that might be problematic is rounding that has to occur for values with decimal points – 33.333% of 1000 pixels would be 333.33 pixels, and the browser has to round that down to 333 pixels. Should the resized image have an actual height of 334 pixels however, it would just flow out of the area the placeholder div is spanning up by that one pixel. May depend on the actual layout (and your fetish for pixel-perfect accuracy) whether that’s acceptable or not.