Space between list items in IE
This article was originally published 13 April, 2005, when
the concept of IE's hasLayout was just beginning to be
studied. MSFT did not
publically document the property to any great extent, as it
was meant to be an internal thing. Unfortunately for us, the
issue of hasLayout affected IE's rendering to the extent the
developer community, at least those who cared about cross
browser compatibility, has spent entirely too much time with
its vagaries.
CSSCreator
IE7 has apparently fixed this particular bug. This article will apply to legacy IE6 installations.
There are cases in which IE treats the white space
"\n" between </li> and the next
<li> as a literal linefeed. That creates
extra space between list items. So this code,
<ul>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</ul>
which should give you this,
list item list item list item list item,
instead gives this,
list item list item list item list item
The common fix has been to remove the offending white space;
<ul><li>
list item</li><li>
list item</li><li>
list item</li><li>
list item</li>
</ul>
<ul><
li>list item</li><
li>list item</li><
li>list item</li><
li>list item</li><
/ul>
<ul><li>list item</li><!--
--><li>list item</li><!--
--><li>list item</li><!--
--><li>list item</li><!--
--></ul>
That works, but is ugly. In the case of non-trivial lists, the formatting can make the list code all but unreadable. Plus, jiggering the html formatting to control display is just wrong.
I thought I had found the secret to the IE white space bug in lists, but there were 'issues'. A bulleted list had screwy placement of the bullets. As long as you don't need the bullets, all is well. I don't think that little caveat makes for a good cure. So the search was restarted.
I figured I had discovered the trigger to be whether the
list item was dimensioned, eg. the width set. From that I
figured MSIE's
hasLayout was involved. There was another clue, and I glommed
onto the wrong one. The trigger is actually a link with
{display: block;}1. You may see this in the following test
cases;
-
<ul id="plain"> <li>list item</li> <li>list item</li> <li>list item</li> <li>list item</li> </ul> -
<ul id="inline-links"> <li><a href="#">some inline link</a></li> <li><a href="#">some link</a></li> <li><a href="#">some link</a></li> <li><a href="#">some link</a></li> </ul> -
#block-links a { display: block; } ========== <ul id="block-links"> <li><a href="#">some block link</a></li> <li><a href="#">some link</a></li> <li><a href="#">some link</a></li> <li><a href="#">some link</a> </li> </ul>
Only #3 will exhibit the white space bug. So an
undimensioned <li> is not the prime mover.
Will setting a dimension do away with the extra space? Yes.
That only corroborates the evidence that this is a hasLayout
related 'feature'.
Here's a live example (view in IE6):
* html #hacked-li li {
height: 1px;
}
==========
<ul id="hacked-li">
<li><a href="#">some block link</a> hacked li</li>
<li><a href="#">some link</a></li>
<li><a href="#">some link</a> </li>
<li><a href="#">some link</a></li>
</ul>
- some block linkhacked li
- some link
- some link
- some link
Notice the bullets. They go to the bottom of the list item. They're too low on a single line, and opposite the last line on multi-line list items. I used the Holly hack to trigger hasLayout, but all methods do the same or worse.
Properties and corresponding values that, if set, cause an element to have layout2.
CSS property: Value
--------------------
display: inline-block
height: any value
float: left or right
*max-height: any value
*max-width: any value
*min-height: any value
*min-width: any value
*overflow: not visible
position: absolute
width: any value
writing-mode: tb-rl
zoom: any value
*added with IE7
The hasLayout property applied to the
<li> fixes the white space bug but causes
its own set of problems. MS says hasLayout applies to anchors,
too. Since the anchor caused the problem, can it fix it?
Live example, view in IE6.
* html #hacked-link a {
height: 1px;
}
==========
<ul id="hacked-link">
<li><a href="#">some block link</a>hacked link</li>
<li><a href="#">some link</a> </li>
<li><a href="#">some link</a></li>
<li><a href="#">some link</a> </li>
</ul>
- some block link hacked link
- some link
- some link
- some link
Why, yes. Yes, it does, and without the shifted bullets. I think I can now declare a general fix for the IE white space bug. Cause the anchor element to have hasLayout=true. The full test case5 should bear me out.
All that, and I did run into another fairly unknown
fix3. Give the
<li> a bottom border! How simple is that? It
has limitations on where it can be used, but when it can …
And yet another fix is found4. This has already been mentioned,
{display: inline-block;}, as setting
hasLayout=true. What is new is that we can use that as a
trigger, then go to {display: block;} without
un-setting hasLayout. So, doing The following will set
hasLayout, but the {display: block;} will
apply as overruling the earlier display value.
a {
display: inline-block;
}
a {
display: block;
}
Notes
-
Hicks Design
(original link is broken) - hasLayout property (MSDN)
See also Ingo Chao's On Having Layout - css-discuss
- Claire Campbell's tripswitch hack
- test case