Can I use `<img srcset>` or `<picture>` for image size rather than viewport size?
Asked Answered
R

1

5

I'm trying to use <img srcset /> to load images based on the size they'll appear on the page, rather than based on the size of the viewport. Perhaps examples will help:

  • On any viewport, when the image is styled with width: 100% inside a 200px-wide <div>, img-200.jpg should load.
  • On any viewport, when the image is styled with width: 100% inside a 400px-wide <div>, img-400.jpg should load.
  • ...etc.

I've done tons of Googling, but as best as I can tell, srcset is only used for changing images based on viewport size, not image size, if that makes sense. Is that correct? Or is there hope for what I'm trying to accomplish?

Retarder answered 11/12, 2017 at 10:14 Comment(6)
Your assumption is correct - the graphic gets chosen by screen resolution, not by container size. So this is not the right approach. Let me think.Eddieeddina
How is it decided what width the divs have? Do they have different classes, is it a percentage of the window width etc?Eddieeddina
@MrLister Just whatever width they happen to appear on the page. It's not so much about the container divs as it is about how big the image itself will be. I was hoping browsers would be smart enough to say, "If the image appears at 200px wide based on the layout and the container element it's in, choose the best image for that size."Retarder
Phrased like that, it's a good question. In fact, it's a shame this doesn't exist yet!Eddieeddina
I was very disappointed when looking at ‘sizes’ that image width isn’t the deciding factor. Seems like a huge oversight. When developing components rather than pages we don’t always know how our components will fit inside their parent. The sizes attribute do any for me solve any problems because that’s not how I design pages :( plus I’m still confused how retina images fit into this - I have to specify more media queries potentially for the same image size? At least with an angular component when the image is created I already know a lot more about the context to choose an image size myself.Duester
I do see now that media can be a standalone attribute on source so that srcset can still contain 1x, 2x images. I've decided in the end to probably never use sizes (because it's ambiguous how this will work with 2x images as far as I can tell). Then I programatically created max-width queries calculated for a percentage of common viewports I'm seeing. Since I only do 100% width on small screens that's ok I guess. html.spec.whatwg.org/multipage/images.html#srcset-attributesDuester
E
5

As was mentioned in the comments, this doesn't exist yet.
However, I've been thinking. If you don't mind a little trickery, there's a workaround.
We can use an iframe.

To the contents of an iframe, its width is the viewport. So then we can use the standard srcset tricks.

Let's say our img looks like this

<img src="https://placehold.it/200x100" alt=""
  srcset="https://placehold.it/200x100 200w, https://placehold.it/500x250 500w">

using the 200x100 image at smaller resolutions (200px or less) and the 500x250 one at higher resolutions.
We can then put this in a HTML file with a zero margin around it, because the iframe expects an actual HTML document.

Now to avoid having to load multiple files, we can turn this into a data URL, which will look as follows:

data:text/html;charset=utf-8,%3Cbody style='margin%3A0'%3E%3Cimg src='https%3A//placehold.it/200x100' srcset='https%3A//placehold.it/200x100 200w, https%3A//placehold.it/500x250 500w

and all that will make our original HTML page look something like this.
Note that, to show it works, I included two iframes, which are identical in themselves. Only their CSS widths differ.

iframe {width:200px; height:100px}
iframe ~ iframe {width:400px; height:200px}
<iframe src="data:text/html;charset=utf-8,%3Cbody style='margin%3A0'%3E%3Cimg src='https%3A//placehold.it/200x100' srcset='https%3A//placehold.it/200x100 200w, https%3A//placehold.it/500x250 500w' alt=''%3E" frameborder="0">?</iframe>
<br><br>
<iframe src="data:text/html;charset=utf-8,%3Cbody style='margin%3A0'%3E%3Cimg src='https%3A//placehold.it/200x100' srcset='https%3A//placehold.it/200x100 200w, https%3A//placehold.it/500x250 500w' alt=''%3E" frameborder="0">?</iframe>
Eddieeddina answered 12/12, 2017 at 21:6 Comment(5)
I see this is iffy on Chrome - sometimes it works, more often it uses the larger image for both iframes. Not yet entirely sure why, sorry.Eddieeddina
Apparently Chrome caches the largest version of the image and uses it for smaller viewports too, once it has loaded it.Eddieeddina
That... is an extremely innovative solution. Wow. I'll try this out—thanks!Retarder
The sneakiness of this made me smile :) I just don’t any faith it will work well in practice though :-(Duester
Also you need to watch out for iframes on safari. The viewport isn’t always the size of the iframe. I think you need to disable scrollingDuester

© 2022 - 2024 — McMap. All rights reserved.