The Internet Explorer hasLayout Property

In a perfect world, we shouldn’t need to know anything about the hasLayout property—after all, it’s an internal component of the Windows Internet Explorer rendering engine. Its effect, however, is far reaching, and has major consequences for the appearance and behavior of elements, affecting how an element bounds its content and reacts with its neighbors.

This topic is solely concerned with Internet Explorer for Windows.

What Is the hasLayout Property?

In Internet Explorer, an element is either responsible for sizing and arranging its own contents, or relies on a parent element to size and arrange its contents.

In order to accommodate these two different concepts, the rendering engine makes use of a property called hasLayout that can have the values true or false for the element concerned. We say an element gains a layout or has a layout when the hasLayout property has the value true.1

When an element has a layout, it is responsible for sizing and positioning itself and possibly any descendant elements.2 In simple terms, this means that the element takes more care of itself and its contents, instead of relying on an ancestor element to do all the work. Therefore, some elements will have a layout by default, though the majority do not.

Elements that are responsible for arranging their own contents will have a layout by default, and include the following (this list is not exhaustive):

  • body and html (in standards mode)
  • table, tr, th, td
  • img
  • hr
  • input, button, file, select, textarea, fieldset
  • marquee
  • frameset, frame, iframe
  • objects, applets, embed

The main reasons Microsoft gives for the fact that not all elements have a layout by default are “performance and simplicity.” If all elements had a layout by default, a detrimental effect on performance and memory usage would result.

So why should any of us even care about the hasLayout property? Because many Internet Explorer display inconsistencies which can be attributed to this property.

In most cases, the issues caused by elements that lack a layout are easy to spot: the content is often misplaced or completely missing. For example, when an element, such as a div, that doesn’t have a layout by default, contains floated or absolutely positioned content, it will often exhibit strange and buggy behavior. The types of strange behavior that can arise are varied, and include such behaviors as missing or misplaced content, or elements that fail to redraw fully while a window is moved or scrolled.3

If you notice that a piece of your content appears and disappears, and sections of the page only get half-drawn, these are good indications that an element requires a layout. When the key element gains a layout, the problem miraculously goes away. In fact, 99% of the Internet Explorer CSS bugs you encounter on a daily basis can be fixed using a hasLayout fix in the correct place. A hasLayout fix involves nothing more than declaring a CSS property that causes an element to gain a layout, when it wouldn’t ordinarily have a layout by default.

The simplest way for an element to gain a layout is for it to have a dimensional CSS property applied—for example, a width or height. However, in situations where you don’t wish to apply a specific width or height to the element, there are several other CSS properties that, when you apply them to the element, will cause that element to gain a layout.

Those other properties are:

  • display: inline-block
  • height: (any value except auto)
  • float: (left or right)
  • position: absolute
  • width: (any value except auto)
  • writing-mode: tb-rl
  • zoom: (any value except normal)4

Internet Explorer 7 has some additional properties that cause an element to gain a layout (this is not an exhaustive list):

  • min-height: (any value)
  • max-height: (any value except none)
  • min-width: (any value)
  • max-width: (any value except none)
  • overflow: (any value except visible)
  • overflow-x: (any value except visible)
  • overflow-y: (any value except visible)5
  • position: fixed

Declaring any of these CSS properties will cause the element to gain a layout—assuming, of course, that the property is valid for the element concerned. For example, we can’t apply a height to inline elements unless the document is being run in quirks mode.

It’s not a good idea to give all elements a layout—not just because of the performance and memory issues already mentioned, but because a number of other unwanted CSS side effects will occur. For example:

  • Children of absolutely positioned or floated elements will not shrink to wrap their content when the child has a layout.
  • Static content positioned next to a float will not wrap around the float, but will instead form a rectangular block to the side of the float.

More examples of unwanted behavior are documented on the MSDN web site.

Debugging hasLayout Issues

If you notice that your web page is behaving strangely in Internet Explorer, try setting a CSS property for an element in order to cause it to gain a layout, and see if the problem vanishes.

Some skill is involved in identifying the correct element to which the property should be applied. With experience, it can become easy to identify the culprit—it’ll usually be a parent container for which no explicit width is set, or whose width is defined by margins alone. If this parent element contains floated or absolute elements, it’s likely to be the one causing the problem; the problems are likely to exist because it’s not taking proper care of its child elements.

A useful approach to debugging layout issues is to set the proprietary CSS property zoom to 1 for elements within the document, one at time, in order to isolate the element that’s causing the problem. If you set the property on an element, and the issue is resolved, you know you’re on the right track. The zoom property is useful because, as well as being a property that triggers an element to gain a layout, in most cases, setting it will not alter the look of the page in any other way (apart from possibly fixing the bug that you’re experiencing). A process of elimination can be used to narrow the problem down quite quickly.

Once you have found the element that’s causing the problem, you can apply the necessary fix. The preferred approach is to set one or more dimensional CSS properties on the element. However, if dimensions can’t be applied normally, a workaround must be employed.

For Internet Explorer 7, the best approach is to set the min-height property to 0; this technique is harmless, since 0 is the initial value for the property anyway. There’s no need to hide the property from other browsers—which is definitely not the case with our next suggestion!

The standard approach for triggering an element to gain a layout in Internet Explorer 6 and earlier versions is to set the height property to 1%, as long as the overflow property is not set to anything except visible. This approach exploits a bug in these browser versions whereby if the overflow property is set to the default value of visible, the height of a containing box will expand to fit its contents regardless of the height property’s value. However, most other browsers will respect the height value of 1%, which is usually not what you want them to do, so this declaration will need to be hidden from all other browsers.

In previous years, the technique of setting height to 1%, and hiding the declaration from all browsers except Internet Explorer 6 and earlier versions, was known as the Holly hack. These days, the recommended method for specifying CSS declarations for Internet Explorer only is through the use of conditional comments.

The good news is that Internet Explorer 7 is a lot more robust than previous versions, and many (though not all, unfortunately) of the issues concerning layout have disappeared—you’ll need far fewer fixes than you might have in previous versions of the browser. For more information about the layout issue, see “On Having Layout” at the Satzansatz web site.

Footnotes

1 Once an element has a layout, the hasLayout property can be queried by the rendering engine or through scripting.

2 If a descendant element also has a layout it is responsible for sizing itself and any descendants, but it is positioned by the ancestor element’s layout.

3 A detailed description of some examples of these behaviors can be found at the Position Is Everything web site at http://positioniseverything.net/explorer.html.

4 zoom and writing-mode are proprietary Internet Explorer CSS properties, and will not pass CSS validation.

5 overflow-x and overflow-y are proposed property names for CSS3, but have been proprietary CSS properties in Internet Explorer since version 5.

User-contributed notes

ID:
#8
Contributed:
by Suzy
Date:
Sat, 25 Jul 2009 18:46:42 GMT

Indeed Paul, zoom:1 is by far the easiest - & thanks for the theory lesson :)

my post, the quoted comments which I think were cut? Were written before inline-block was more widely supported - namely Firefox although IE6/7 still doesn't support it properly, without this trip, on block level elements. Hence the need to trip the display property back to what it should be (either block or inline).

Note: inline-block; added to an element alone is not enough to make it act like a block if that is the required behaviour from the layouted element. Nor is it safe to assume default inline behaviour in all cases. see: http://www.brunildo.org/test/InlineBlockLayout.html, so again that was/is my reasons for tripping it back to what it should be

inline-block added to a block level element will mean the element will no longer auto fit its parent. So tripping it back just keeps all browsers/stylesheets on an even keel without needing to calculate specific widths or heights or guess how different browsers (or indeed IE) would handle the proper behaviour of inline-block itself

The last rule you show will of course set hasLayout by order of the cascade, but leaves the display of the element as an inline-block, that may be perfectly fine as you say, but check previous link, especially now with the x-browser support as good as it is - so advice is, use zoom: 1; or if using tripswitch, then still 'trip' it back to what you want please

I am a bit conscientious about this behaviour because I never wittingly invented a "hack", I just discovered a behaviour by accident. I have always advocated if using for hasLayout trigger to 'trip it back' and to comment it to that effect too, to avoid unexpected things happening (e.g. people copy paste, doesn't work as expected, they blame person who told them that.. in this case that would be you, and we can't have that!) - http://onhavinglayout.fwpf-webdesign.de/hack_management/#method-comparison - picked it up why I still defend it ;)

I'm not sure that having different rules in the same ruleset fails to make it work is like the old !important hack, but instead is merely the cascade working properly, i.e. it ignores the first declaration. Why it works in different rulesets I presume is because it is actually applying the first rule (rather than ignoring it) then subsequently overruling with the second. (i.e. setting the hasLayout part of it but not overruling it as it can't be changed once set)

Authors should note that width and height would be needed to make inline-blocks act like a proper block (fill its parent) in which case width and height both trigger hasLayout too so if the original element was a actual inline element the trip back to display:block; is possibly simpler than calculating and carrying widths/heights through especially if borders/padding involved. If it's a block level element then width/height can be used by themselves to trigger haslayout, so there would be no need to trip the display property at all ** ;)

LOL, after all that, zoom: 1; is easier of course in a conditional stylesheet, and is the one I would use mostly. If you are already using the Holly Hack in a conditional stylesheet, and like it because you know it - it's still advisable to change it to zoom:1; as it has proved unstable in rare cases see: http://www.brunildo.org/test/relayout.html

[** aside]
The inline-block "tripswitch" is also a method to force inline-block to work on block level elements in IE6/7 which is how I would mainly use it, it just has the benefit of adding hasLayout at the same time, which is normally needed when doing this anyway ;)

In short the inline-block (tripswitch) method is as safe as the zoom method, but the tripswitch validates and has other uses too, namely being able to use inline-block on block level elements in IE6/7, which I think is going to prove much more useful going forward

ID:
#7
Contributed:
by peterkp
Date:
Sat, 16 May 2009 01:45:08 GMT

"So why should any of us even care about the hasLayout property? Because many Internet Explorer display inconsistencies which can be attributed to this property."

The idea is clear, but the grammar could read more clearly. Maybe you mean something like "many Internet Explorer browsers display..." or "Because Internet Explorer often displays..."

ID:
#6
Contributed:
by Paul O'B
Date:
Mon, 25 Aug 2008 18:14:37 GMT

re: comments below:
"----------------
The following should cause A elements to gain a layout:

a {display:inline-block;}
a {display:block;}

But this would not:

a {
display:inline-block;
display:block;
}
-------------"

For elements that are naturally inline such as a elements then all that is needed to trigger "haslayout" is to use one of the properties that trigger "haslayout" (as listed in the reference above). However the "trigger" must be a property that applies to inline elements which is why you can't use width or height as a trigger on inline elements.

An inline element can simply have zoom:1.0 applied and no other properties need be supplied in separate rules. The inline-block value also applies to inline elements and is also a trigger for "haslayout" so for inline elements then display:inline-block can be used and no other rules are required.

There is no need to re-state the display:block in a separate rule as it is not needed here at all.

This will do just fine.

a {display:inline-block;}

or even

a{zoom:1.0}

The reason that the following example fails to gain "haslayout" is probably the same reason that the "!important hack" works and is used to target IE.

a {
display:inline-block;
display:block;
}

IE only seems to apply the latter property/value it sees when there's more than one property with the same name in the same rule. The element never gets a chance to "gain haslayout" because IE only sees and applies the display:block in that rule.

Therefore this rule will still apply "haslayout":

a {
display:block;
display:inline-block;
}

IE ignores the display:block and only applies the display:inline-block

That's the theory anyway.

ID:
#4
Contributed:
by GrandMaster7
Date:
Tue, 04 Mar 2008 10:49:27 GMT

Typo:

"...proprietary CSS property zoom to 1 for elements within the document, one at time, in order..."

"one at time" should be "one at a time"

Covering the IE haslayout property, some bugs it can cause, and how to go about fixing them is very helpful. Thanks! :)

ID:
#3
Contributed:
by lose_the_grimm
Date:
Fri, 22 Feb 2008 18:56:36 GMT

"So why should any of us even care about the hasLayout property? Because many Internet Explorer display inconsistencies which can be attributed to this property."

Omit the word "which" in the second sentence.

Related Products