Responsive images – how to prevent reflow

October 10, 2012

This is what we have been taught in the past: “To prevent reflows, specify the width and height of all images, either in the HTML <img> tag, or in CSS.” (Source).

And in responsive web design we are taught to not specify width and height of images, but to make them flexible with: img{max-width:100%;}. So in order to get the flexibility that responsive images offers we need to sacrifice some rendering speed. Right?

I am sure you have experienced reflow on mobile sites on a bad connection: you load a page, start to read the page, scroll down and then the content seemingly “jumps up and down” because of the reflow. This is because the browser does not know the dimensions of the image so it cannot reserve space for it. So when the image is loaded, it will have to insert it into the page, and move away everything that is below and right of it and do a reflow.

UPDATE: The following technique is based on an article I wrote about responsive embeds that again is based on an article by Thierry Koblentz called Creating Intrinsic Ratios for Video.

I have put up a test page that simulates a slow connection so that we all can experience the pain together. To feel maximum pain, scroll down right after you load up the page. Experience reflow.

Still there? Great, hope there were minimal casualties.

A solution

There is one prerequisite to this solution: you need to know the aspect ratio of the image. Let me explain the technique.

No more img{max-width:100%}

Yes, that is correct. We are not using one of the most fundamental things in responsive web design. Instead we use the responsive embeds technique. This means that we set a wrapper div around the image and use the “padding-bottom” trick to make a div that keeps a certain aspect ratio:

The markup

<div class="embed-container ratio-16-9">
      <img src="imgage.jpg"/>
</div>

The CSS, we add a few aspect ratios that we can use in our code:

.embed-container {
    position: relative;    
    height: 0;
    overflow: hidden;
    background-color:black;   
}

.ratio-16-9{
    padding-bottom:56.25%; /* 9/16*100 */
}

.ratio-4-3{
    padding-bottom:75%; /* 3/4*100 */
}

.ratio-1-1{
	padding-bottom:100%; /* ... */	
}

Then, it’s just a matter of setting the image to position:absolute and top left aligned:

.embed-container img{
    position: absolute;
    top: 0;
    left: 0;
    width:100%;
}

Voila.

Sidenote: You can also use preprocessors like LESS to calculate the padding for you:

@ratio-16-9: (9%/16%*100%);
@ratio-4-3: (3%/4%*100%);
@ratio-1-1: (100%);

.ratio-16-9{padding-bottom: @ratio-16-9;}
.ratio-4-3{padding-bottom: @ratio-4-3;}
.ratio-1-1{padding-bottom: @ratio-1-1;}

How about max-width?

Since height of the div is calculated based on width on the parent div, we need to set max-width on the parent div if we want to limit the size of the image. This can be a drawback, but since the whole technique is based on that you know something about your images, it should be possible.

The result – demo

And if we use the same technique as before to simulate a slow connection you can see that we now have a reserved space for the image (I use black background for clarity. And again, scroll down to experience the lack of reflow): The demo without reflow!

In this technique we reserve space for responsive content without specifying widht or height in pixels and we are not using JavaScript to calculate dimensions. Comments? Does anyone have alternative solutions?

UPDATE: A follow up article on how to also lazy load and multiserve images using this technique is here.

Tags:, , ,

Categorised in: ,

Written by Anders M. Andersen

  • http://saurabhworld.in/ Saurabh Kumar

    what about the images which does not have pre-determined aspect ratio?

  • Clark Pan

    I don’t think avoid a reflow if you know nothing about the image thats being served (because how would you be able to set the width and height attribute for a non-responsive image).

    If you’re serving this image out of a cms, then i think inlining the padding-bottom on the element would be acceptable.

  • Brian FitzGerald

    Dude! This technique is awesome. I scoured the web for this information and yours is the best (dare I say only) article on the topic I found. Thanks a million!

  • Brian FitzGerald

    Dude! This technique is awesome. I scoured the web for this information and yours is the best (dare I say only) article on the topic I found. Thanks a million!

  • http://mgakashim.com/ Artful Dodger

    Nice work. I dunno though. Seems like an awful lot of work. There should be an easier way than this.

  • http://mgakashim.com/ Artful Dodger

    Nice work. I dunno though. Seems like an awful lot of work. There should be an easier way than this.

  • FremyCompany

    Nice trick. However, if I was you, I would replace the “img” tag with a background image on your div (and background-size: cover or contain). That would avoid you the position trick, the overflow trick, and a lot of work for the browser.

  • FremyCompany

    Also, this works even if you don’t know the exact aspect ratio (because it can vary). The result will just be that a small part of the image is cropped (cover) or that the image doesn’t fill the width at 100% every time (contain).

  • http://twitter.com/Clevertail Clevertail

    I’m on my cell so I can’t tell, your example site page used CSS refreshing?

  • thierrykoblentz

    This is a trick I wrote about on A List Apart: http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/

    I’d have expected a mention about it in this article.

  • http://amobil.se Anders M. Andersen

    Sorry about that Thierry, I referenced you in an earlier article about this, but the article is now updated!

  • http://amobil.se Anders M. Andersen

    Thanks, that is an alternative solution. It solves many of these issues and you can also use media queries to multiserve them, but I am not a fan of putting content in the stylesheet, images belongs in the HTML in my opinion.

  • Bmcquade

    Yes, I think background-size has its uses and developers should be aware of that technique. But I believe both of these techniques are useful in different contexts and neither is a substitute for the other.

    If your goal is to prevent a reflow and to display the whole responsive image without cropping, you must tell the browser what the aspect ratio of that image is. Otherwise the browser will need to reflow once it parses the image’s headers and discovers the image’s actual width and height.

  • Peppe

    Thanks, it has been very usefull for me as I was trying with no success to do someting similar with a background-image, but It was always cropped

  • Peppe

    Thanks, it has been very usefull for me as I was trying with no success to do someting similar with a background-image, but It was always cropped

  • Nathan Taylor

    Curious – i’m keen to use this technique. On existing sites which I cannot change the front-end HTML structure, but am looking to make responsive, could I use the anchor tag wrapped around the image. Obviously the image would be need to be the only child of it’s parent. I’m struggling to see any issues with this use. Obviously using a div container is preferable. Thanks

  • Pingback: Rules to build and Optimiize Web pages – Google | sureshat25()

© 2014 Copyright.