Blog (my web musings)

Find out what's interesting me, get tips, advice, and code gems that don't fit elsewhere.


Search Blog


Images can be tricky to deal with in a responsive environment; by nature they are a static element with specific dimensions, so how can we manipulate them into working with our lovely fluid / flexible web layouts? Thankfully there are a few techniques, and this post rounds up my top 3.

Please note, this article mostly covers visual resizing in a web browser, and not any true responsive image techniques, i.e. serving different images to different screen sizes. These are just some ways to manipulate one image - the same image presented using 3 different methods. 2 of the 3 techniques below can be adapted to serve big images to desktop and small images to mobile - I'll cover that in a later post.

Method #1 - Fixed Ratio Resize

Demo

Let's look at the 1st image resizing technique - for this demo I'll call it the Fixed Ratio Resize method.

Resize your browser window and you'll see that it's a really simple way to shrink images, without any frills. The aspect ratio is maintained regardless of how skinny the window gets, and it can be conveniently applied to a standard <img> element with these few lines of CSS;

<style>
.fixed-ratio-resize { /* basic responsive img */
    max-width: 100%;
    height: auto;
    width: auto\9; /* IE8 */
}
</style>

<img class="fixed-ratio-resize" src="students.jpg" alt=""/>

Browser support for this is very good and works all the way back to IE7.

One glaringly obvious fail in this method is that horizontal images can resize to ugly proportions in relation to surrounding content. Just take a look at the sample banner image and see how when the browser is pulled in very small, the image all but disappears (Ow, feel my squinty eye-pain!). Now imagine this in use on a smart phone - it isn't doing a very good job of giving illustrative meaning to content, is it? Worse still, see what happens when placed alongside a more traditionally proportioned portrait photo - see how completely overwhelming the thistle pic becomes, compared to the horizontal banner? Let's take back some control...

Method #2 - Target Ratio Resize

Demo

This is based on a technique I came across a few years ago; a way of resizing YouTube videos while maintaining aspect ratio. It was pioneered by Thierry Koblentz and presented on A List Apart in 2009: Creating Intrinsic Ratios for Video, and is based on the idea of using internal top or bottom padding on a container element, to directly influence the height of a child element. This works because padding values declared as percentages in CSS, are relative to an element's width, and will proportionally resize as the width does. This also means that the padding "presses" on whatever it's sat up against, forcing it to resize too. Put it on the top or the bottom of an element and it will proportionally affect the height of the child. Phew! With that explained, take a look at the Target Ratio Resize method demo. Please note that while I am using the same padding-percentage concept, I decided to use it on a pseudo element to eliminate the extra container div (cleaner markup).

I call it the Target Ratio Resize method because the element that is being resized will shrink down to the aspect ratio you tell it to, based on the specified padding-top percentage;

<style>
.target-ratio-resize {
    max-width: 960px; /* actual img width */
    max-height: 150px; /* actual img height */
    *height: 150px; /* actual img height - IE7 */
    background-image: url(/students.jpg);
    background-size: cover;
    background-position: center;
}
.target-ratio-resize:after {
    content: " ";
    display: block;
    width: 100%;
    padding-top: 33.333%; /* 3:1 ratio */
}
</style>

<div class="target-ratio-resize"></div>
  • for a final 3:1 aspect ratio: 1 / 3 * 100 = padding-top: 33.333%;
  • for a final 4:3 aspect ratio: 3 / 4 * 100 = padding-top: 25%;
  • for a final 16:9 aspect ratio: 9 / 16 * 100 = padding-top: 56.25%;

This doesn't create a completely smooth scale-down though - notice how when the browser window is pulled-in, only the banner image width shrinks to begin with, until it hits the padding-top / aspect ratio threshold, and then the height is affected too. Because of this non-linear scale-down, it too can result in a disproportionate text-to-image relationship in responsive layouts. No way near as bad as the 1st method, but it could still cause visual inconsistencies. This method IMO tends to work best on a collection of uniform / standard image sizes, for example, in a CMS where users are likely to upload regularly-sized 4:3 or 16:9 camera images. Deploy this technique alongside a PHP auto-resizing script, and the results would be nicely and predictably proportional.

Support is good in IE9+ and modern browsers that support background-size:cover;. In IE8, the height and width shrinks but the image inside does not resize, while in IE7, only the width shrinks but height stays the same, and again, the image does not resize. It's not completely horrible though, and you'll probably be serving a fixed-width layout to IE7/8 users that doesn't need image / content / layout resizing (no support for media queries so less responsive design considerations).

The last technique takes the most work to setup BUT it offers the most predictable and controllable results...

Method #3 - Fluid Ratio Resize

Demo

I learned about this technique, that I'm calling the Fluid Ratio Resize method, about a year ago in a voormedia article for fluid aspect ratios. Read the article for more info, but in a nutshell, this method builds on #2 to give a smooth linear scale-down when the image resizes, thanks to the calculation of a "sloping scale". This "slope" transforms the image from a large size / aspect ratio, and gradually scales it to a smaller size with different aspect ratio. The smooth, linear slope of the resize behaviour is what makes this technique a real gem for predictable responsive design. The downside is that you need to know the start and end size for it to work well, which means it isn't something that could easily be incorporated into user-generated content. It is most definitely something that you as a developer can use in layouts though. Again, I have eliminated the extra container element used in the voormedia article in favour of a pseudo element;

<style>
.fluid-ratio-resize {
    max-width: 960px; /* actual img width */
    *height: 150px; /* actual img height - IE7 */
    background-image: url(/students.jpg);
    background-size: cover;
    background-position: center;
}
.fluid-ratio-resize:after {
    content: " ";
    display: block;
    width: 100%;
    padding-top: 4.918%; /* slope */
    height: 102.786px; /* start height */
}
</style>

<div class="fluid-ratio-resize"></div>

There are some nice illustrations in the voormedia article for fluid aspect ratios that explain how the "slope" is derived and, in turn, how the padding-top and height are calculated, so please do check it out. For convenience (and for the sake of my brain and yours) I've created a Fluid Ratio Resize Calculator that does all the hard work for us. Just plum in the source (actual) image dimensions, then enter the target dimensions, and out pops the padding-top and height values without anyone breaking a sweat!

Support? Same as #2.

Side-by-Side Examples

Demo

Here you can see the behaviour of all 3 techniques side-by-side. Click the "Hide Text" button so the images sit closer onscreen, then get squishy with the browser window to see how their resizing behaviour differs.

What if the focal point of the image is not in the centre?

It's probably safe to assume that the most interesting images tend not to have their focal point (or area of interest) located smack bang in the middle - it will probably be off to the side (rule of thirds and all). No problem. You can easily change the focal point of the image, to make it resize around the thing of interest, by customising the background-position.

Right-edge focal point = background-position: 100% 50%;

Demo

(the boys are 100% across the image)

Custom focal point = background-position: 85% 50%;

Demo

(the dancer's face is about 85% across the image)