Feb 17 '08

I Can hasLayout

I don’t pretend to understand each and every one of the intricacies that make browsers behave differently. But one I have basically figured out, and one that causes the majority of most people’s fits, is actually pretty easy to fix. It’s the mysterious and frustrating hasLayout property.

hasLayout is a somewhat obscure yet very important CSS attribute that has been done away with by virtually all modern browsers… except of course the ubiquitous thorn in our sides that is Internet Exploder. Now, in the interest of fairness, it has been confirmed by the Microsoft team in recent weeks that the pending release of IE8 (who knows when that will come) will finally do away with the hasLayout property once and for all since IE8 will finally be a fully compliant browser. But, since we don’t live in Neverland, let’s focus on reality.

So what is this obscure property? Well, in short, hasLayout is a proprietary property developed by the IE team that determines how certain HTML elements render, and more importantly how they affect other elements around them. It’s a boolean property, and while it defaults to to false for most elements, there are certain definitions that set the property to true on their own without warning. For instance, a plain old <div> tag is not a “layout” element by default (hasLayout = false), but when floated, it clicks its heels together and poof! It now, magically, “hasLayout”! Go figure. So what do we do about this wicked witch who’s out of control behavior breaks our pages?

Simple — we zoom that bitch. Huh? Okay, let’s back up…

The commonly used HTML elements that “have layout” by default are: <html>, <body>, <table>, <tr>, <th>, <td>, <img>, <input>, <select>, <textarea>, <fieldset>, <iframe>, <embed>, and <object>.

And the commonly used CSS attributes that trigger hasLayout are: display: inline-block, height: [any value except auto], width: [any value except auto], float: [left or right], position: absolute, and as of IE7 you can include min-width: [any value], min-height: [any value], max-width: [any value except auto], max-height: [any value except auto], and overflow: [any value].

Sheesh, that’s a lot of crap, eh? I could spend time explaining how and why they are what they are, but CSS is all about saving time so let’s make like we stole something. Basically, the crux of the issue is that any element which does not have layout by default (the list above) that is then assigned a value in that second list above will begin to exhibit unusual behavior like disappearing backgrounds, excess margins, etc.

So what do we do? Well, we could manually fix each item, but there’s a better one… one attribute I left out of the list. It’s a little bugger called zoom. Applying the simple definition of zoom: 1 to the parent element of your items that are experiencing layout issues will solve all your woes. Setting the zoom property as such will cause your floating elements to snap back in position, it will fix the magic disappearing background bug we all love so much, and plenty of other lovely surprises IE has in store for us. Sure, there are other fixes for these issues like applying position: relative to floating elements to fix the background issue, or applying height: 1% to the offending parties to give them layout, a la the now famous “Holly Hack” (look it up). But the bottom line is that all those methods have unintended consequences. The height fix, for instance, causes issues if you use the very handy overflow property to control various floating elements or images in certain instances. So why mess with all these different possibilities when you can rely on old faithful: zoom: 1.

What does it do? Well, zoom is actually an obscure property that’s meant more for Javascript use than anything else. As its name would imply, zoom handles an attribute that allows you to change the magnification of an element, usually via Javascript. The beauty of it in CSS land, however, is that unlike those other methods mentioned above, it has no detrimental effect on the page’s rendering… except of course changing the hasLayout value of the element to which its assigned, which is actually want we want, no more and no less. That’s it, no complicated combination of stars and slashes to hack your way through. Just assign that value (sometimes if you have nested elements you’ll need to tinker with which one actually needs the definition, but usually it’s the parent) and you’re good to go.

Leave Some Bon Mot