Reflections on max-width

Posted on 5th of July 2008

A couple of years ago, I added a page to my old site on an “easy” fix for emulating max-width behavior in Internet Explorer, by utilizing a powerful IE5 feature called dynamix properties/expressions.

Briefly, these expressions allow a web author to hook script expressions into the dynamic nature of HTML elements. The natural events of the page (onresize, onclick, onmouseover and so on) causing these expressions to be re-evaluated whenever content could possibly reflow. The effect is naturally very powerful.

<html>
<head>
<style>
#container {
width:expression(this.parentElement.clientWidth-100);
background-color:red;}
</style>
</head>
<body style="background-color:blue;">
<div id="container">foo</div>
</body>
</html>

The effect is unique, and should be obvious to anyone that this allows for very powerful behavior.

A problem of foresight

I’ll try to explain the motive for posting my old article, max-width in Internet Explorer. First off, at the time I was studying alot of HCI. So while making a HTML site for a school related project, I saw a good excuse for sounding clever about line-widths. Even with most of that stuff holding true, I simply didn’t think through the ramifications of posting this “hack”. And for a large part, I simply wanted to sell the expression technique, as I feel it’s extremely powerful, and many developers are unfamiliar with it. So I cooked up what seemed at the time as a “elegant” solution to this max-width problem.

I’ve received more email about this article then anything else ever on my site (quick hit in my inbox says hundreds of mails containing max-width). I still receive mail about it, with IE7 supporting max-width and the related properties. So, for a very long time, I’ve wanted to “set things straight”, and I shall attempt to do this here.

Not for the faint-hearted

As I noted, expressions are very powerful. To fully utilize and appreciate raw expressions you need a solid understanding of scripting, stylesheets and how they interact in Internet Explorer, and especially you need to understand how IE works, with “standards mode“, and the old-time box-model.

“Houston, we have a problem”

So, let’s explorer some of the problems we can run into. First off, this technique may look like a style in the presentation given above, but it’s behavior is anything but. First off, the expression construct used above is simply “short hand” for the setExpression function. This means that once IE encounters the expression construct it binds the code directly to the object. If you use any fancy DOM work to disable either the entire stylesheet (stylesheet switching) or just to kill a single element, it won’t work as the expression is already bound to the actual elements. It should be easy to see in this example where you can easily kill the stylesheet, but observe how the background-color style sticks regardless.

Far side of the moon

Let’s examine the actual code I posted in that old article. You can see the example of a simulated max-width here, but remember this only works in IE.

<html>
<style>
body {
width:100%;
margin:0;
padding:0;}

p {
border:1px solid red;
max-width:800px;
width:expression(document.body.clientWidth > 800? "800px": "auto" );
}
</style>
<body>
<p>
[alot of text]
</p>
</body>
</html>

If you try it out in IE, it’s perfect. The red line is never past the view port of the browser, never does any scroll bar appear, and so on. It looks like a spot on emulation (and for this little example, it is). The code is deceptively simple, if body.clientWidth is more then 800 pixels wide, then we enforce a width of 800 pixels. Super simple and straight forward right?

Now, what assumptions are at work here? Well, a huge assumption is that the body element (or rather, the containing box of the content we wish to apply a maximum width to has no padding and/or margin. Another (more dangerous assumption) is that the box model applied is the old non-standards compliant box model. Another problem is that we’re working in pixels. The entire point of the article was to discuss line-lenghts. Falling back on the pixel defeats that idea. The basic problem is that it’s just so hard to retrieve information about an elements size using relative units, so I just “wing” it a bit in the article, which helps no one.

Crashing hard

Now, let’s see what happens when we change some of those assumptions. First off, including a proper DOCTYPE in the document causes IE to change the box model used. This will cause borders, padding, etc to not be counted towards the width of the element. This in itself isn’t so bad, it merely causes the “effect” to appear more jittery.

It’s far worse, if you try to apply the max-width to an element whose own width is dependent on the elements contained within. Reflowing content causes the onresize event to fire, which in turn may cause an infinite loop. Look at the following code same code from before. WARNING: this code is designed to hang your browser if you use any older version of Internet Explorer.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
body {
width:100%;
margin:0;
padding:0;}

div {
background-color:green;}

p {
border:10px solid red;
padding:10px;
margin:10px;
width:expression(foo());
}
</style>
</head>
<body>
<div id="ctb">
<p>
<script>
document.write(document.compatMode);

function foo() {
	return (ctb.offsetWidth > 800 ? "auto" : "800px");
}
</script>
[alot of text]
</p>

</div>
</body>
</html>

Things to note is that a DOCTYPE has been added, a containing box for the paragraph has been added, and some margins and padding added as well. If you attempt to run this code in IE6 (seems this has been fixed for IE7), the browser simply locks up hard, and here’s why. The paragraph will tell itself to be 800 pixels wide when the ctb element shrinks to any less (min-width). Now due to the padding and margins I’ve added, the paragraphs width will add up to 820 pixels. This will cause the ctb element to widen to contain it, and suddenly it’s wider then 800 pixels, and poof, the script expression thinks the width should be auto. The paragraph, with it’s new setting of width: auto; snaps down in width, to fit within the browser window, and in turn, meaning that ctb can size down as well, and then the whole affair just starts over. And infinite loop, and it locks the browser up.

And I think locking the browser up in this manner is about as crappily as you can treat any visitor to your site.

As aside, I can note that there has been some fixes to IE, to prevent the browser from hanging. First off, the above code actually works in IE 7. It hangs IE 6. But in order to cause it to hang, I had to swap the code out into it’s own function. If I inline the code, IE 6 just ignores the code completely, presumably using some heuristics to sniff out that this isn’t really code it wants to execute.

Solutions

I think the time for solutions is well past. Back in the day, Dead Edwards had a fancy HTC you could add to pages, to make IE implement all sorts of CSS properties, including max-width (seems he continues to do this). I would probably have recommended that, as that was probably a more solid drag-and-drop solution.

At any rate, I’ve always had a sour taste in my mouth with my old page, and I’ve tried a sort of carthasis with this post, trying to wash some of it out. I’ve never been a fan of the popular “hacks” that started to develop once Cascading Stylesheets started to catch on like wildfire. It seems to me, that relying on broken behavior in very specific versions of browsers is just stupid. It’s basicly against everything most web developers wish for when they look at a page rendering in Firefox and IE, and wish they looked the same. Refusing to accept a “blemish” on your page, and instead resorting to hacks (of which mine was admittedly the worst) to make sure your vision is presented faithfully to the visitor just smacks of arrogance to me.

I’ve long since stopped working at the yoke of the visual designers with photoshop files being sent my way by, and as such, I’m not entirely sure how the industry works in practise. But I sincerely hope that it has matured enough to accept imperfections, and see them for what they really are; an expression of the open nature of the web.

Littering our pages with browser specific hacks is no better then client sniffing code. Each time we introduce a browser specific feature on our sites, the web gets to be a little bit messier. The IE team at Microsoft has a pertinent article on what writing these browsers are like.

Tags: , , , ,

8 Responses to “Reflections on max-width”

  1. Timothy Says:

    I want to thank you for this. I was racking my brain trying to figure out why IE wouldn’t render properly even though I was working with the standard. I will be visiting often from now on.

    Keep up the good work.

  2. Nataliya Says:

    I found your blog searching for “min/max width in css/html”. This is so cool what you wrote! Thank you for that.

  3. svendtofte Says:

    It’s worth noting that CSS expressions will probably be disabled in IE8 as part of the effort to increase browser security. They will still work in “IE 7 mode”, but this is still great motivation to not use these techniques unless you have substantial knowledge on these matters.. And while I don’t get as much mail as I used to about this, the thing simply is that if you can’t figure it out for yourself, you simply don’t know enough about the subject matter to implement such a brittle and dangerous work-around.

    http://blogs.msdn.com/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx

  4. flash tekkie Says:

    Any script execution at the Style Sheet stack of the browser is a performance issue and more importantly a security threat so the use of IE expressions should not be encouraged. It’s a non-standard approach that does not comply with W3C directives.

    Good news is Microsoft is ending expressions in Internet Explorer as announced on Thursday earlier this week. Indeed a very nice move towards the standard-compliant browser.

  5. Chad Lester Says:

    Thanks for your post on this subject. However, it seems that there is a much simpler solution that works in every browser I tested: IE 6, IE 7, FireFox 3 (on Mac and PC) and Safari. With two nested tables:

    Your content goes here.

    What I have found is that “width” on a TD element is interpreted to mean: grow up to this width unless I’m constrained by my parent.

    The inner table is not really necessary unless your content might be smaller than the 40em and want a border or background color to shrink to the size of your content (in which case the style goes on the inner TD). It has no width assignment (width=auto), so it will grow to be just as big as is needed to hold the contents, but never bigger than the constraining parent.

    FYI, I was using:

    Granted, this is a lot of extra markup and hence, still sort of a hack. But it seems less hacky than using expression syntax to me.

    Am I missing something?

    Caveat - I have not read and understood the W3C table layout rules well enough to know if my solution is standards compliant. I only know that it works on the browsers I tested.

    The “expression” syntax is still worth knowing.
    Thanks,
    Chad

  6. Chad Lester Says:

    Frustratingly, all of my html was stripped out and I’m not sure how to post my example - I’ll use square brackets instead.

    [table][tr][td style="width:40em;"][table][tr][td]

    Your content goes here

    [/td][/tr][/table][/td][/tr][/table]

    Hope that works.

  7. Mauvis Ledford Says:

    @svend: I agree that the expression feature can be dangerous and in most cases the wrong tool to use, except in this exact circumstance and paired with an IE conditional statement.

    @Chad: I’d rather use conditional CSS for the one browser that needs it (IE6) than switch to tables unnecessarily. Additionally, the above approach can work with limiting the size of things like embeds and other content without having to wrap each element in a table.

  8. HotPotatoe Says:

    Hi there, nice article and clear explanation.
    I have a question fron which I haven’t seen any answer yet.
    I have a website done in flash 100%.
    I want this website to be inside a layer and I want this layer to grow free and expand to fill the user’s browser till certain point, this is: A máximun width of 1600px and a máximun heigth of 1000px. (I can live without fixing the height if necessary) The flash movie inside the div has it’s size set to 100% width and heigth. If you apply this hack, or the JELLO MOLD hack, or at least every hack I have found on the Web, the content of the layer (the swf movie) wont be displayed in IE!! It just dissappear!!
    It seems like because of it’s relative width and height (100%) it doesn’t have a solid presence to make it’s container expand…
    Try it yourself, you will see what I mean.
    Can anybody bring me some help about this topic?

Leave a Reply