A flexible layout isn’t all that flexible if some of the component parts are fixed. Text easily reflows as it’s container resizes, but what about images and other media? How do we make them flexible to keep our layout flexible?
Last week we talked about elastic layouts and flexible grids. Next week we’ll look at media queries. We’re building toward responsive layouts by discussing each of the 3 parts necessary for responsive design in a separate post.
All the credit here belongs to Ethan Marcotte and I recommend his post on flexible images. I also highly recommend Ethan’s new book on responsive design.
Also Richard Rutter has set up a page experimenting with flexible images using max-width that’s worth checking out.
How to Create Flexible Images
Typically when adding an image to a web page we set a width and height using absolute measurements like ‘px’. Unfortunately this fixes the image size and is completely inflexible.
At one specific point the absolutely fixed image is probably the perfect size. However in all other cases it will either be too large or too small for the layout. Let’s consider the case where the image is larger than its container.
We already know how to keep elements from growing too large and that’s through the max-width property
{code type=css}
img {
max-width: 100%
}
{/code}
And with that one line of code we’ll prevent our images from ever being larger than their containers. And since we’ve set the measurement in % the image can resize itself as its container resizes.
If an image is larger than it’s container it will be scaled back to be the same size as the container. If the image is smaller than the container the image will be its default size.
Modern browsers are good at maintaining proportions so the image will resize well as the layout resizes. This works not only with images, but with video and other media. We can refine the above css to be:
{code type=css}
img, embed, object, video {
max-width: 100%
}
{/code}
And we’re done. This is all seeming too easy isn’t it? Unfortunately we’re not there yet. The above doesn’t quite work everywhere.
Internet Explorer 6
First up is IE6, which probably isn’t any surprise. It may also not be much of a problem depending on your site. IE6 is finally falling out of use so it’s up to you whether or not it’s worth supporting.
IE6 doesn’t support max-width, but it treats the width property similar to max-width. The simple fix then is to use a conditional comment targeting IE6 and then set the width to 100%.
This will force all images to be the same size as the container. It works great if the image is larger than the container, but for images meant to be smaller like thumbnails and icons the images will scale up and usually not look too good.
We could go through the trouble of wrapping each of these smaller images inside its own container and set additional css on the containers, but that’s probably more work than it’s worth.
You can also apply a fix using Microsoft’s expression() property, though it usually takes some trial and error to get the values you need correct.
For my part I’ve stopped developing for IE6 unless specifically requested and paid for by a client. On this site IE6 use has dropped to less than ½%
Windows
We’ve either taken care of IE6 or ignored it, but we’re still not done. Unfortunately Windows the platform doesn’t scale images as well as it could. Resized images can look pretty bad due to a bug in the operating system.
Fortunately while the issue is with the platform it only affects a few specific versions of browsers.
The browsers in question are Firefox 2, and IE 7 and below. The issue doesn’t affect other modern browsers. It also appears as though the bug has been fixed in IE7 so we’re actually down to IE6 and FF2 as browsers we need to find a workaround for.
The solution for IE6 (again should you choose to support it) is to use Microsoft’s AlphaImageLoader filter.
You may be familiar with AlphaImageLoader since it’s also used in a fix for transparent .pngs on IE. Since it’s Microsoft specific though it won’t work with FF2.
I’m willing to concede that we probably don’t need to support FF2 and as I said above I’ve stopped supporting IE6 as well.
Odds are you probably aren’t going to support either of them so instead of presenting details of the fix here I’ll once again point you to Ethan’s post on flexible images, which includes a javascript fix and a few more details about the issue and solution.
Background Images
We’re close, but still not all the way to having flexible images everywhere. If you’ve noticed we’ve been talking about images directly in your html so far. What about background images declared in your css?
Vertically Repeated Images
A couple of weeks ago I posted 4 methods for creating equal height columns in css and the first of those methods was faux columns. In that method we set a fixed width background image on a container div and repeated it vertically to mimic the background behind the individual columns.
While in that post we used a fixed width image, the method can be extended to be a little more flexible, if we’re willing to apply a little math.
Let’s use the image from the faux columns post (seen above) as an example. The image was 960px wide and transitioned at 340px from the left edge. First we’ll use the hopefully familiar formula we used to create elastic grids.
target ÷ context = result
340px ÷ 960px = 35.4167%
Now we know where our transition point is located relative to the edge.
Next we’ll create a much larger background image than we’ll reasonably need and once again do the math in reverse to determine where we need to set that transition point.
Let’s create an image that’s 3000px wide.
target ÷ 3000px = 35.4167%
Doing the math our target becomes 1062.5 px. Since we need to use integer values in Photoshop we’ll round up to 1063 px.
Finally we’ll set the image using the css background-position property.
{code type=css}
background: url(“background-image.png”) repeat-y 35.4167% 0;
{/code}
Our image can now scale with our layout while our transition point will always remain where we want.
The above works for vertically repeating background images, but it’s not truly flexible in the sense that we’ve created a fixed width image, just one much larger than we think we’ll ever need.
We’ll be ok as long as the layout doesn’t get wider than the image, but that may not always be the case.
Horizontally Repeating Images
If you have a small image that you’re using as a repeating background there shouldn’t be any issue. The image will repeat to fill up its container regardless of size.
Assuming the image is small enough horizontally or represents something that only changes vertically (think gradient on a navigation bar), the worst case is being off a couple of px at the edge, which is unlikely to be noticed by most.
Background-Size
CSS3 has a property called background-size, which would be perfect, but at the moment it’s not supported well enough to use in practice.
Next week we’ll talk about media queries, which will let us set different images over a range of layout widths. In time the combination of media queries and background-size will be our solution, but sadly not today.
Hiding Images with Overflow
Much of the time max-width alone will be enough to keep your layouts flexible. At times though your images won’t scale well because of the content of the image or perhaps it’s not really necessary to always show the entire image.
If we set overflow: hidden on a container around an image then as the container is resized smaller than the image, part of the image will be hidden. The image won’t be flexible, but it will preserve the integrity of your layout and allow it to remain flexible.
Most of the time max-width will be the better option, but depending on the content in the image it may also be ok to hide it instead of resizing it.
Image Replacement
There’s one last method which involves replacing images that might be useful when your image is complex enough that scaling it doesn’t work well and where hiding part of the image isn’t an option.
The solution is to use multiple images and serve different sized images under different conditions.
This is a server side method and instead of presenting it incorrectly here I’ll direct you to a post by Bryan Rieger on mobile image replacement with the details and even better a download with all the code you need.
Next week we’ll dive into media queries which also allow you to serve different images based on device and screen width among other things.
Summary
Being able to create flexible images is an important consideration when trying to create a flexible layout. What good is a flexible layout if the content inside forces the layout to be rigid?
For most cases all we need to do is set a max-width of 100% on our images (and media) to make them flexible. You’ll need a couple of fixes for IE6 and one for FF2 should you decide you need to support those browsers.
With vertically repeating background images we’ll create much larger images than necessary and use a little math to understand where to set transition points on the background-position property.
At times we can apply an overflow: hidden fix that will preserve the flexibility of our layout even if they don’t make our images any more flexible.
In time we’ll have browser support for the css3 background-resize property, but for now max-width: 100% and overflow: hidden should cover most cases.
Even with all of the above methods we don’t have a way to create flexible images 100% of the time. We are able to cover most practical cases and perhaps rethink our use of images in those few cases we can’t yet cover.
Next week we’ll continue with a discussion of media queries before wrapping up with some thoughts about responsive design.
Download a free sample from my book, Design Fundamentals.
Hi, nice succinct article, one thing i´ve been struggling with is setting max-width on dynamiclly sized images, for example the various wordpress thumbnail sizes, any tips would be great!
Thanks Danny. Good question. I usually don’t create images that dynamically resize so I’m honestly not sure of any tips at the moment. I did just make a note to research it and hopefully find enough to write a post. I’ll try to experiment some too.
What kind of issues are you seeing?
Hi Steven, thanks for the reply.
Generally what happens is the width and height attributes get written inline, therefore overwriting the max-width:100% set in the stylesheet, although I´m not really comfortable with it, adding !important seems to work OK. The major problem however, is the height attribute, because it´s fixed in pixels, resizing the browser will indeed adjust the width to fit, but results in a distorted image as the height doesn’t change.
I hope that makes sense & thanks again.
Is WordPress adding the inline styles then? Or is it your theme? I can see how inline styles would cause problems. I wouldn’t think WordPress would do that since it’s usually good at leaving the styling to designers, but I suppose it’s possible.
Ideally there’s a way to get rid of the inline styles. Otherwise you might have to use !important to override them, but that is a less than ideal solution.
Set height:auto; and the height will scale as the width changes
Thanks Kevin. I’m not sure why I didn’t say that above. It’s exactly what I do here. 🙂
great post…I’ve struggled a bit with this method, especially with IE. This helps.
No doubt I’m doing SOMETHING wrong. Nonetheless: I’ve specified a jpeg with no height, no width; and I’ve specified max-width=100% for img files in my CSS. Yet, on my iPod Touch the jpg doesn’t “shrink to fit”. Grrr. Likely something about the way I’ve diddled the viewport meta (width=device-width, as Apple suggests…)
How are you defining mx-width. It should be:
max-width: 100%
in your css. It might be that the containing element to the image has height and width explicitly set so it always remains at that set size, which means the image will fill 100% of the containing element.
The containing element has an explicit size as a percentage: max-width:85% but the @media spec blows that away for smaller screens with max-width:none. I suppose I should be going “mobile first” with @media spec for *larger* screens and simply put my max-width:85% *there*.
If you’re using max-widths everywhere things should get smaller as the screen gets smaller.
If you can’t figure it out feel free to send me a link if this is online or just email me the code. I’ll be happy to take a look.
(A long time later!) I’m now using absolutely no height/width in html, viewport as described, CSS with max-width:100%. It works as you described. Density on my part, for which, my apologies. Where it fails is on mi esposa’s oil painting slide show, using jquery nivo-slider, which likes sizes specified. Works on iPad, not very iPhone-friendly. That’s life. Thanks for your kind and generous attention!
Thank you so much for img {max-width: 100%; height: auto } ! New to the web and teaching myself HTML5 and CSS and tearing my hair out because I couldn’t figure out how to create CSS rules figure and figcaption to get my images of different sizes to display correctly. This solves my problem. Thanks again. Susan
Glad I could help you save some of your hair. 🙂
Hi.. you have not explained how to do it for the any image.. which is not repetitive.. pls help me out in this how can i resize the image using css for different resolutions?
I’m not sure I understand your question. Could you provide more details about what you’re trying to do?
@fjpoblam – No worries about the time passing. 🙂
Just so you know I’m back to adding width on height on images that are coded into the html. If you have both
max-width: 100%
height: auto
in your css then the images will resize just like you want. The reason for adding the dimensions in html is it helps browsers to display the image quicker.
That might even fix the problem you’re having with the jQuery plugin.
Thank you for a useful article. I was good to go already on the first explanation of max-width.
I am confused when it comes to background, repeating images. If bckground image repeats AND resize, how do you know how many images appear “per square inch”? On a small iphone screen, would you get a hundred tiny images repeated just as many times as they were on the big screen?
Thanks Ketil. Good question about background images. It isn’t anything I’ve specifically tested, but I would think your background image remains the same size and it would only repeat if there’s more space to fill. You wouldn’t get hundreds of tiny images in other words, but less of your original image.
Using an HTML5 doctype will kill the use of image width and height in percentages :sigh:
Remove the doctype altogether and it works again (ie html 4 mode).
I use max-width: 100% on images all the time with an html5 doctype and it works fine. In the htmlI still specify the image width and height in px and I also add image {height: auto} in my css.
That works to have the images be flexible. They won’t grow larger than the width and height set in the html, but that’s generally not a good idea anyway as the quality would quickly degrade.
height:auto is nice for fullscreen, but not for constraining an image on a mobile device such to allow other information (eg float:left) on the image.
You can use max-width on the image to constrain it. Set image {max-width: 100%} and the image won’t be wider than the container it’s in.
however max-width:55% is a non-proportional change, whereas width:55% preserved the image aspect ratio :sigh:
If you use height: auto is should preserve the aspect ratio.
Good Morning, I have a single page with a table where I inserted a panorama viewer, displaying a panorama picture, and next to it another static image. Everthing is working fine but I am experience difficulty to make it responsive – battling for the last 3 months now. Is it possible that you can assist me – willing to compensate you.
Kind Regards, Johan
Hi Johan. I wouldn’t have time to assist at the moment, but if the page in question is online, feel free to post a link to it. I might be able to spot something.
What specifically isn’t working when you try to make it responsive?