Hacker News new | past | comments | ask | show | jobs | submit login
How to Use Responsive Images (ycombinator.com)
89 points by yoav on Apr 28, 2017 | hide | past | favorite | 32 comments

If you are using Webpack to build your application, you can take advantage of a fantastic loader called "responsive-loader" [0] which can automatically build smaller and smaller versions of an image which can be dumped into a srcSet automatically to give you a good amount of the benefits of responsive images without a ton of work customizing each <img> tag in your application.

Combine that with my plugin "imagemin-webpack-plugin" [1] which will ensure they are all compressed as well as you want, and you can get a fairly drop-in solution to massively reduce the size of images downloaded while keeping extremely high resolutions for user agents that want it, and without a ton of manual work on your part!

I've always wanted to look into taking this a step further and somehow determine the actual size of the image on the screen in various resolutions and then generate more accurate image sizes and fill in the `sizes` attribute. I've thought that you might be able to pull it off with some automated headless browsing of the built app with some work, but I never got around to trying it.

[0] https://github.com/herrstucki/responsive-loader

[1] https://github.com/Klathmon/imagemin-webpack-plugin

Fantastic! The webpack ecosystem maybe fiddly and overwhelming, but as soon as you have a nice, solid selection of tools wired up and working it becomes very powerful. I'm really excited about the two packages you mention. :D Thank you for sharing this!

I get why this is done, and it is important. But look at the amount of effort and time that goes into displaying a single image properly on the web nowadays. It's just nuts.

It feels like we are slaves to the tech and not the other way around.

You should read up on Client Hints. Allows the browser to automatically send desired size and pixel density down the image request, where the CDN can then serve up the appropriate file. Basically means for most cases you could go back to using a single <img> tag.

It's Chrome only for now but it's a nice future.

If you are using images from a vector source, SVG is supported by all modern browsers and naturally provides all this for free. However for smaller resolutions, PNG may result in a lower file size.

I feel like this is just performance tuning. Serving a single image is fine for most cases and it's not harder than it used to be. If you want a huge image for hi-res desktops and a smaller one for phones, you only need one of those CSS tricks (the "srcset" one).

You can always outsource the work to a service like WebFlow or Cloudinary to lessen the workload.

What is the compatibility with older browsers? Useful to know when designing for countries with expensive bandwidth or outdated smart phones

Regarding bandwidth, adding responsive images should reduce bandwidth consumption because it downloads a smaller version of the image.

As long as you provide a `src` attribute, older browsers will just ignore the `srcset/sizes` attributes and work like always. So it's backward compatible.

Author here if anyone has follow up about the post, ama.

Nifty post. Always think the world could stand to learn more about srcset/sizes.

About a year ago, I went all the way down the rabbit hole of programmatically generating `srcset` attributes and wrote about it:


What I'm curious about is the strategy behind publishing hands-on technical posts on the Y Combinator blog. Is it just to give it some street cred among programmers?

When an article is about responsive images, I expect it to at least mention the <picture> element, if only to explain why the article will not discuss it.

Thoughts on SVG sprites?

Not a web expert here, but don't CSS media queries and "background-image: url(blah/blah/blah.jpg)" already achieve pretty much all of this?

With the advantage that you have attributes (background-size, etc) to handle image resizing and alignment without having to faff around with imgs, divs to contain said imgs and a bunch of CSS rules for each for hours?

AND the advantage that you can have one single file for "media" definitions that allows you to swap images around when needed (just change the url()) without having touch 347 HTML files just to set the image src?

Or maybe I am missing the point.

You could do that, but there's a performance benefit to doing it with srcset/sizes in the html.

The cascading part of CSS means the a later rule could override an earlier one, so to determine which image variant to download when looking at the css the browser needs to parse the html, parse the css, link the two. A css rule may end up not even applying to any elements on the page if a particular selector has no matches. Only after all this can it begin downloading the actual images.

Using srcset/sizes the browser parses the html and can begin downloading the correct image variants immediately, before it parses css.

With prefetching enabled this means your browser could parse the html and cache all the image variants on the page that you'll need when hovering over a link to another page. So when you actually click on it everything is loaded from cache and super fast.

It's up the browser to manage situations of lower network speed, pixel density, etc. and to determine when and how much preloading to do. Using srcset/sizes just gives the browser the option to optimize as much as needed.

I think I understand what you are saying.

I did not consider the overhead of the browser parsing the CSS file and then figuring out which rules are applied where and depending on what rules are being applied, figuring out what else needs to be downloaded, etc.

But is that overhead really that significant? Or will the responsive images approach merely shave off a few % off the page load time?

While I think that the overhead on it's own might not be that much, even little gains of tens of MS can add up to improve the experience.

And something like srcSet will possibly allow the useragent to become "smarter" in the future. Perhaps halving image size when low on battery, or when on a limited mobile plan.

This isn't you choosing which image to serve who as a developer, it's serving up a bunch of options and letting the useragent choose which it knows is best for the user at that time.

In the case of preloading. The performance you're shaving off is all the time it takes to download all the images on your page. Which can be significant.

If you're on a slow connection, it can make a page load like it was loading from cache. Which can be quite significant compared to the css approach.

The question of whether the time spent implementing the feature is worth the benefits for a particular project / audience will vary on your use case.

That would require you know all image urls ahead of time and include them in your css file. For something like a blog or a site with user uploaded content you'd be getting the image url from your database when generating the page.

You can still make responsive images without using them as a background. Just set the CSS width property to 100% of its parent and the height property to auto. The problem is you can certainly over-scale if the parent container's width is larger than the image's.

Agreed. Was responding to the top comment in this thread about why one might want to use an image tag instead of background-image.

Yes, you can do all that, which was the more common way of having responsive elements without all the fancy new tech. It seems this post is talking about only loading the size you need.

What you're describing can mean loading something large and resizing responsively -- which can result in enlarged photos or wasted bytes to load an image of a size you don't need.

This is an interesting approach for people who don't mind cluttering their HTML, but want to scale media appropriately.

My cursory reading indicates that with media queries, the browser is smart enough to only downloads the images that match the media query.

So you could have media queries for small size, medium size and large size with urls pointing to different images, and only the appropriate image will be downloaded and applied, thus achieving the same effect.

There's no accent in the article that images should be optimized for the target screen dpi. It's wasteful to serve a 2x image for 1x screens and 1x when 2x is already present on the page.

Almost all CDNs/services compress images lightly if at all, offline tools are better at this, e.g. images from the reference page can be ~20% smaller. Ideally, hidpi images should be compressed harder, e.g. lower JPEG quality.

Great points. The first article only lightly touches on those topics, in part 2 I'll talk more about the challenges and constraints that lead us to the srcset widths we use at Webflow and our image processing / compression stack.

Hopefully talking about the 'why' will help others make the right choices for their project.

The reference page will see improvements in the future as we enhance our process, but certainly resizing and optimizing variants by hand can yield even better results if you have the time.

What is worth noting from part 1 is that using pixel width variants in `srcset` will let the browser factor in dpi of your monitor as part of the calculation. So it wouldn't serve a 2x image where it only needed 1x.

It's not recommended to use high dpi images, 72dpi is the way to go for web content, with a larger (dimensions) version serving as the 2x variant.

Recently learnt in more depth around this, and did a really fun project to automate this in an ASP.net control.

Input is:

    <Controls:ResponsiveImageFixedSize runat="server"
Renders as:

    <img width="43" height="44" srcset="https://s2.construct.net/images/v173/r/global/construct-3-logo_v43.png 1x, https://s2.construct.net/images/v173/r/global/construct-3-logo_v64.png 1.5x, https://s2.construct.net/images/v173/r/global/construct-3-logo_v90.png 2x, https://s3.construct.net/images/v173/r/global/construct-3-logo_v110.png 2.5x, https://s3.construct.net/images/v173/r/global/construct-3-logo_v130.png 3x" src="https://s2.construct.net/images/v173/r/global/construct-3-logo_v43.png" alt="Logo"/>
Works and looks great on high dpi displays. Lazy loading enabled renders something like:

    <img class="jsEnabled" data-src="https://s1.construct.net/images/v173/r/home/monster_v350.png" width="350" height="367" data-srcset="https://s1.construct.net/images/v173/r/home/monster_v350.png 1x, https://s1.construct.net/images/v173/r/home/monster_v550.png 1.5x, https://s3.construct.net/images/v173/home/monster.png 2x" src="https://s1.construct.net/images/v173/1.gif" alt="Monster"/>
        <img width="350" height="367" srcset="https://s1.construct.net/images/v173/r/home/monster_v350.png 1x, https://s1.construct.net/images/v173/r/home/monster_v550.png 1.5x, https://s3.construct.net/images/v173/home/monster.png 2x" src="https://s1.construct.net/images/v173/r/home/monster_v350.png" alt="Monster"/>
At this point I was thinking that's actually a fair old chunk of text to display an image, but still worth doing.

It can be quite fiddly doing this, but it's nice when it's done and works as expected!

If SVGs were embraced more broadly (and the standards team supported) many of the raster images would fall to the wayside. These recommendations are still totally valid for content-based images (photos, etc.).

Some sort of hybrid between the two, and the recs in the article, seem to be the future of visual imagery online.

I'd love to also see something like FLIF get browser support. http://flif.info/ where the user agent could set a preferred quality for images/variants based on network/device constraints. Or download the first say 20% of images on a page, only downloading more after staying on the page for a length of time.

Umm... How do I get to the post? It just takes me to the HN homepage.

Maybe it's my ad blocker on iOS.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact