CSS bugs bonanza

How max-width fails in IE8

Flexible, fluid, liquid, responsive - layouts which don't rely on a fixed width have had a comeback recently. The CSS max-width property is veryuseful in these designs. So is the knowledge about related browser bugs. Enter IE8.

Images and max-width

When max-width is applied to an <img> tag, the effect should not be restricted to the width of the image. The height has to be adjusted as well, unless there is another rule explicitly setting a value for it.

For instance, a stylesheet might define a width: 100% to make an image fill its container, but limit its size to max-with: 200px. The browser will use both rules to calculate the effective width and, absent any directives for the height, rescale the image: The height is set in proportion to the width. This preserves the aspect ratio of the image and avoids ugly distortions.

This behaviour actually applies to any replaced element that has an intrinsic ratio of width and height. In practice, though, this means images.

What IE8 makes of it

Yet unfortunately IE8 doesn't play by the rules. When both width and max-width are specified and the max-width limit is the lower of the two, the limit should be binding. Indeed, IE8 applies max-width to the width of the image, just as it should.

But the image height remains as if the max-width limit had not come into effect: IE8 calculates the height in proportion to the overridden width rule. The affected images are compressed horizontally (or stretched vertically, depending on how you look at it). This bug is an IE8 peculiarity - it didn't exist in IE7, and has vanished again in IE9.

This is what it looks like:

In IE8

In standards-compliant browsers

If you'd like to see it on a live page, have a look at the demo. (Of course, you'll only be seeing the distortion if you are viewing the page in IE8.)

How to fix it

There are two ways to deal with this problem, both of them straightforward.

Solution #1: Fix the CSS

The key to making IE8 behave is setting a max-height in proportion to max-width. Suppose an image is 200px wide and 100px tall - and here we are taking about the dimensions of the actual image file, not the display size imposed on it with CSS. Now if max-width limits the image to 50px, max-height should be set to 25px. Done.

The catch is that you have to know the image size in advance. Obviously, this is not an issue with static pages. But if your content is coming out of a CMS, it might be impossible to hard-code these values into the CSS.

Solution #2: Use a script for dynamic pages

Instead of writing fixed max-width values into a CSS file, they can be generated on the fly. This is exactly what the jQuery script below does.

Usage is simple. Put a conditional comment for IE8 in your page source. Within it, load a copy of the jQuery library if it isn't available already, then load the script. That's all there is to it.

This solution may also be useful for static pages. Including the script makes the IE8 bug a non-issue, so it might make sense to use it on every relevant page and just forget about the problem. Again, the script should be wrapped in a conditional comment, as above.

Potential issues, including those caused by IE's caching and by slow connections, should be covered just fine. For more details about how the script works, just have a look at the commented source.

Setting "width: auto" on the img-tag will fix this in a much cleaner way.

"But I want to have my image cover 50% of the container", you might say. Well, there's a simple fix for that kind of scenario. Wrap the image in a div and set the div to to be 50% wide instead. Image will be width: auto and thus seem to have the 50% width.

You are right about width: auto (and that's why the polyfill doesn't kick in if it is set, see the source).

But I don't think adding extra markup to the page, just to fix an isolated browser bug, is in any way cleaner than dropping in a script in a conditional comment targeting IE8 only.

I'd go for an uncluttered document structure for reasons of readability, but also because using a div as a hack is not self-explanatory. You'd need a comment along with each of those divs if other people are working on the site, and perhaps for your future self as well.

No, not really, and honestly I don't think this is a matter of taste or coding style, but rather one of maintainability.

A percentage width of 100% could be handled by width: auto, unless an image needs to scale up beyond its native size - so that part would basically work. Other percentage widths would require additional markup, though, as an IE8-specific hack (see the comment above by Johnzzon, and my reply). Browser bugs really shouldn't be fixed by sprinkling random bits of HTML across a site. Those fixes are very likely to break when the HTML is refactored.

A JS-based, targeted bugfix, when added to the base page template, requires zero administrative effort, restricts the performance penalty (additional request) to IE8, and allows you and anyone else on the team to forget about the issue entirely.

Unless you are dead sure you won't need any other image scaling than width: auto anyway, a blanket fix is better than individual repairs. If you ask me. Which you haven't ;)

Don't really get what you're saying. Just set everything to width auto on the first line of the stylesheet, and then, as far as I understand, IE8 behaves (in his respect, anyway) the same as other browsers. No IE hacks or extra bits of HTML are required. (And this in itself is not an hack, but perfectly regular, valid CSS, setting the property to the value it has by default in other browsers.)

If, for example, an image needed to expand to fill a sidebar then, e.g.:

#sidebar img { width: 100%; }

will be the CSS you need for all browsers (nothing different or extra for IE8) and will simply override the width: auto already set.

If you disagree, provide me with a specific example where this approach will fail or cause some difficulty.

Oh, that would be a different story altogether. I got you wrong, perhaps because I'd never heard of that hack. In fact, that would be the most elegant solution to the problem.

I have tried your suggestion now, though, and it doesn't have any effect. Here's a quick demo for it. Matters don't improve if the line is added at the top of the default style sheet, either. So, no luck.

(If you think I got the setup wrong, perhaps you can post a link to a working example.)

The real-life situation in which I came across this issue was in a WordPress theme.

What I wanted was for images to stay within their containing element (typically div) and so I was setting max-width: 100%, which, where its effect was to shrink images, was resulting in the width being reduced as needed but the height remaining the same.

In WordPress, when an image is added to a page or post the height and width attributes are automatically set within the actual HTML (as actual HTML attributes, not as part of a style attribute). Although I had NOT specified a CSS width for the image, it seems that IE8 was using the HTML width attribute (larger than the maxwidth) to calculate the height, resulting in the image being stretched heightwise.

My adding * {width: auto} to the stylesheet was overriding the HTML width attribute and allowing the image to scale proportionally. (img {height: auto} was already elsewhere in the stylesheet, else the HTML height would have prevailed.)

In summary, the issue I was experiencing was slightly different from that described on this page and was NOT caused by a CCS width being used to calculate the height, but rather the HTML width attribute. Setting CSS width to auto overrode the HTML width and allowed the image, in the absence of any other CSS width, to scale correctly.

If I had been using a CSS width to size the image then you are quite correct that a script solution, such as yours, would have been needed.

(Finally, to echo the first comment on this page, let's hope than now MS is no longer supporting XP, in the not too distant future we can all stop having to make allowances—and special style sheets—for this wretched browser.)

What you describe is actually the correct way to go about it, and it does indeed work. In your example, you have set

a width and height attribute on the image tag

a width: auto style which overrules those attributes

a max-width: 100% cap on the image width, limiting it to the width of the containing element.

So if you stick the img into a div which is 50px wide, the image will be limited to that 50px width.

My guess is that in your case, the containing element is not limited in its width and is allowed to expand as much as it needs. The max-width cap doesn't apply then, and you are left with width: auto, which will make the image 5000px wide.

How is the actual way to have the script working in IE7 and IE6? You mentioned it could be possible at a computational cost. my plan is to use condition, so i do not have to worry about any extra doings like extra calculations in IE9. thanks so far!!

Not sure what you are referring to ... The script solves a problem in IE8, and IE8 only. There is no need to target IE6 or 7 (apart from the fact that these versions should not be on any developer's plate in 2016).