How can we construct a responsive image tag to insure that the browser chooses the image with the lowest file size that will fill its container, rather than choosing a higher resolution version?
I'm building a website with many images per page. We are more concerned about fast page load than we are with image quality. On a phone with a high resolution screen, we would rather the browser use the low resolution image than selecting a 2x image, for example, even if there is a bit of pixelation evident.
How would we construct an img tag or picture tag to accomplish this?
I've tried this:
<img
src="//placehold.it/992x662"
srcset="//placehold.it/1024x683 1024w,
//placehold.it/992x662 992w,
//placehold.it/768x512 768w,
//placehold.it/544x363 544w"
sizes="(min-width: 1200px) 1024px,
(min-width: 992px) 992px,
(min-width: 768px) 768px,
(min-width: 544px) 544px,
calc(100vw - 30px)"
/>
but Retina phones choose the largest file where we want them to use the smallest one.
I think you need to use <picture> for this:
<picture>
<source media="(min-width: 1024px)" srcset="//placehold.it/1024x683">
<source media="(min-width: 992px)" srcset="//placehold.it/992x662">
<source media="(min-width: 768px)" srcset="//placehold.it/768x512">
<source media="(min-width: 544px)" srcset="//placehold.it/544x363">
<img src="//placehold.it/992x662" />
</picture>
I want my responsive Webpage to load the appropriately sized images. I currently have an HTML template that looks like:
<picture>
<source media="(min-width: 950px)" srcset="{{ .Cover.Large }}">
<source media="(min-width: 600px)" srcset="{{ .Cover.Medium }}">
<source media="(min-width: 300px)" srcset="{{ .Cover.Small }}">
<source media="(min-width: 150px)" srcset="{{ .Cover.Xsmall }}">
<img src="{{ .Cover.Medium }}" alt="{{ .Title }} poster">
</picture>
Large = 950x400
Medium = 600x252
Small = 300x126
Xmall = 150x63
Now I'm thinking this min-width is not going to work very well if the pictures are in a row or flexed. Isn't it best to define the dimensions of the image and let the browser download the most suitable source?
https://html.spec.whatwg.org/multipage/embedded-content.html#valid-source-size-list
What's the cleanest way to do this? Confusingly in my own responsive experiments, the Large size is always loaded:
Picture element
Img srcset
First of all, are you using the same image for each scenario but only in different sizes? If so, you can probably just use the srcset attribute rather than the <picture> element.
The <picture> element is used when you require art direction-based selection, like if you're using a wide shot for the large screen and a portrait crop on a narrow screen, for example. The thing about the <picture> element is that it's used in situations where we want a specific image to display at a specific breakpoint, hence there is no ambiguity in terms of image selection when using the <picture> element.
Which links back to my original question, are you using the same image for each screen width but simply in different sizes? If so, a normal img element with the srcset attribute would serve you much better.
For fluid-width images, srcset will be used with the w descriptor and sizes attribute. There are two values in the sizes attribute. The first is a media condition. The second is the source-size-value, which determines the width of the image given that particular media condition. Below is an example of the srcset syntax:
<img srcset="uswnt-480.jpg 480w,
uswnt-640.jpg 640w,
uswnt-960.jpg 960w,
uswnt-1280.jpg 1280w"
sizes="(max-width: 400px) 100vw,
(max-width: 960px) 75vw,
640px"
src="uswnt-640.jpg" alt="USWNT World Cup victory">
Here, I’m telling the browser that for viewport widths up to 400 pixels, make the image 100% of the viewport width. At viewport widths up to 960 pixels, make the image 75% of the viewport width. And for everything above 960 pixels, make the image 640 pixels. The browser utilises the information from srcset and sizes to serve the image that best matches the stated conditions.
Full disclosure: I lifted a lot of this from an article I wrote previously on this topic
This is what I wanted, 4 images flexed across a screen that are backed with multiple renditions of the JPG in order to save client bandwidth. Note the code is missing a src= attribute to make it valid.
body {
display: flex;
align-items: flex-start;
}
picture {
margin: 1em;
}
<picture>
<img
srcset="https://placeholdit.imgix.net/~text?txtsize=89&txt=XSmall&w=150&h=63 150w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Small&w=300&h=126 300w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Medium&w=600&h=252 600w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Large&w=950&h=400 950w" sizes="calc(25vw - 2em)">
</picture>
<picture>
<img
srcset="https://placeholdit.imgix.net/~text?txtsize=89&txt=XSmall&w=150&h=63 150w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Small&w=300&h=126 300w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Medium&w=600&h=252 600w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Large&w=950&h=400 950w" sizes="calc(25vw - 2em)">
</picture>
<picture>
<img
srcset="https://placeholdit.imgix.net/~text?txtsize=89&txt=XSmall&w=150&h=63 150w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Small&w=300&h=126 300w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Medium&w=600&h=252 600w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Large&w=950&h=400 950w" sizes="calc(25vw - 2em)">
</picture>
<picture>
<img
srcset="https://placeholdit.imgix.net/~text?txtsize=89&txt=XSmall&w=150&h=63 150w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Small&w=300&h=126 300w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Medium&w=600&h=252 600w, https://placeholdit.imgix.net/~text?txtsize=89&txt=Large&w=950&h=400 950w" sizes="calc(25vw - 2em)">
</picture>
So I learnt several things:
How to flex images
picture.img is fine, you don't need to use the source element
learnt about vw the view port size width, which is like a percentage of the screen, but you must you absolute values when calculating margins, e.g. calc(25vw - 2em). 25vw = 1/4 of screen with the picture margins 1em+1em either side
this stuff is really complicated, this example doesn't even use break points, which I would suggest you avoid for your sanity!
It does exactly what I want it to do. It loads the appropriately sized and bandwidth efficient image. If resizing down, it doesn't load a smaller image, which I want. And when it scales up, it does fetch a larger higher resolution image, which I do want in order to avoid any ugly artefacts.
Result: Efficient transfer of several JPG renditions
I am using polyfill for Art Directing two different different kinds of logos - one for desktop and the second one for mobile devices.
<picture>
<source media="(max-width: 25em)"
srcset="logo_mobile.svg">
<source media="(max-width: 48em)"
srcset="logo.svg">
<img src="logo.svg">
</picture>
As I am doing various types of CSS3 Animations (drawing effect and moving gradient) to these Logos, I would like to use the SVG Code Inline.
Is this possible? Thanks.
I am trying to switch a responsive image when it gets down to mobile, at the moment I'm using picturefill.js and also srcset and sizes to do the switching, however the images are not switching from the code used bellow.
<img srcset="/images/marketing/large.png 1190w, /images/marketing/mobile.png 320w"
sizes="(min-width: 767px), (max-width: 768px)"
alt="A rad wolf"
class="img-responsive" />
Your sizes attribute is invalid. With the sizes attribute, you define the display width of your image element. And you can use media conditions to define different breakpoints. You are only using media conditions, but don't add a size.
Example:
sizes="(min-width: 767px) 760px, 100vw"
Which means if the viewport is larger than 767 the image is displayed at 760px otherwise it has the full viewport.
Additionally the first media condition that matches is taken, therefore you don't need to mix min-width and max-width. It is much easier to either use max-width or min-width.
sizes="(min-width: 980px) 980px, 100vw"
The same sizes described with max-width:
sizes="(max-width: 980px) 100vw, 980px"
You can also try to use lazySizes which adds the sizes automatically for you.
I've found a number of posts about hacks for fixing IE8's PNG problem, but I can't seem to adapt any of them to my scenario.
I have four PNGs that are generated dynamically using $.load(). They fade in and out, and then another four PNGs are generated and do the same thing.
In IE8 the semi-transparent parts of the images have black backgrounds.
Is there a way I could run an alpha filter on individual PNGs when they are loaded instead of upfront when the DOM is ready?
Any other suggestions?
Thanks!
You need to use the AlphaImageLoader filter (not <img src="..." />) to display the image.
Even in IE 8, this is necessary to get the filters to play together.