Extra spacing and incorrect height on list items in Internet Explorer

View Comments
dropdown-bug

Good ol’ IE. There’s a fairly common issue with Internet Explorer and CSS, particularly while using list items. This most commonly arises as an issue when developers are making drop down navigation in which the navigational links are listed vertically. In Internet Explorer 6 and 7, vertical lists will have extra space after each list item. This only occurs when the list items and their children are block elements. There are a few fixes, but I recently learned that one of the accepted fixes works in Internet Explorer 6 and Internet Explorer 8, but not Internet Explorer 7.

An example of the problem

First, let’s build a simple example of the problem. We’re going to make a vertical list of links, and use CSS to turn those links into block elements. Generally, this is done so that a user can click a link without actually having to click the text. The markup is as follows:

CSS:

* {
	margin: 0px;
	padding: 0px;
}
ul {
	list-style: none;
	width: 100px;
}
ul li {
	display: block;
}
ul li a {
	display: block;
	color: #fff;
	font-weight: bold;
	background-color: #000;
}

HTML:

<ul>
	<li>
		<a href="javascript:;">Item 1</a>
	</li>
	<li>
		<a href="javascript:;">Item 2</a>
	</li>
	<li>
		<a href="javascript:;">Item 3</a>
	</li>
	<li>
		<a href="javascript:;">Item 4</a>
	</li>
	<li>
		<a href="javascript:;">Item 5</a>
	</li>
</ul>

Output (with screenshot of IE output to the right):

Spaced list in IE6

List with spacing in IE6

I have included a screenshot of the output that is given in IE6 (to the right of the example) for those who are fortunate enough to not be looking at this code snippet in IE6 or IE7. Needless to say, IE has completely failed at rendering this properly. Placing block elements inside of other block elements should not create a mysterious margin. Bad IE, bad.

This bug is known. It was known when IE7 was released. Microsoft didn’t fix it until IE8 was released. So, until then, web developers needed a means to handle it. If this was exclusive to IE6, then we could chalk it up to bad coding and move on. Any user still using IE6 is bound to run into errors all over the internet all of the time, and your error is just another nudge towards an upgrade. However, there are still IE7 users, many of which are actually IE8 users that are using the “Compatibility View” feature.

Non-hack solutions

There are means of getting rid of this bug without applying any CSS hacks or using conditional stylesheets. One method is to give the internal block elements a set height. Sadly, this limits the size of your list items. Another way is to remove all whitespace before the end of the closing </li> tag. It turns out that this whitespace is actually the cause of the problem. Unfortunately, doing so makes your markup look a bit… awkward.

The list with the offending whitespace removed

<ul>
	<li>
		<a href="javascript:;">Item 1</a></li><li>
		<a href="javascript:;">Item 2</a></li><li>
		<a href="javascript:;">Item 3</a></li><li>
		<a href="javascript:;">Item 4</a></li><li>
		<a href="javascript:;">Item 5</a></li> 
</ul>

The small-height hack

The solution that I had found to work was a hack that told IE (and only IE) that the block element in the list had a height of only 1 pixel. This is similar to the above solution where the element is given a height, but it does not apply to other browsers and is visually ignored by IE. This hack works in most circumstances in both IE6 and IE7. In order to apply it, you could either define it in a separate stylesheet, or in the same stylesheet as a hack.

Separate stylesheet

<!--[if IE lte 7]>
<style type="text/css">ul li a { height: 1px; }</style>
<![endif]-->

For those unfamiliar with conditional comments, this uses conditional comments to apply the style to IE versions less than or equal to 7.

Internal stylesheet hack

One way to add the hack is to add a character to the CSS rule, such as the asterisk or underscore. Browsers other than IE will look at this and ignore it, assuming that it’s a typo. IE, however, will attempt to fix the typo and render the styles.

ul li a {
	*height: 1px; /* Only IE will read this rule */
	display: block;
	color: #fff;
	font-weight: bold;
	background-color: #000;
}

Another way to accomplish this is to use the global selector before the html selector. Only IE considers this valid. It is invalid because there are no elements in the DOM that are the parent of the DOM’s root element. That is, unless you are IE.

ul li a {
	display: block;
	color: #fff;
	font-weight: bold;
	background-color: #000;
}
* html ul li a {
	height: 1px;
}

And when that doesn’t work?

On rare occasions, the small-height hack works in IE6 but does not work in IE7. The only reason that I know this is because I have encountered it myself while developing a client’s website.

The incorrect list in IE7

What the list looked like in IE7

The correct list in IE7

What the list was supposed to look like in IE7

Above are images that show what the list looked like in IE7 and what the list should have looked like in IE7: The way that it was somehow rendering in IE6. I am currently still diagnosing what exactly caused this discrepancy, but the client is more concerned with making it work than finding out what caused the problem. This brings me to my new solution.

The inline-block hack

This hack, in my opinion, is clever. As you may or may not know, the display: inline-block rule only works properly on elements in IE that naturally have a display: inline rule. When this is not the case, it simply undoes it’s strange whitespace bug, as well as changes its size (if the width and/or height CSS rules are set to auto). After it is declared an inline-block element, IE treats it as one. Then, in a separate rule, you turn the element into a block element again, and voila! No extra space.

In order to apply this, you have to tell IE that the element is an inline-block element, and then you tell it that the block is a block element in a separate rule. And, because you are redeclaring the element to be block, there’s no need for any improper CSS syntax.

CSS:

ul li a {
	display: inline-block; /* For IE, but anyone can see it */
}
ul li a {
	display: block;
	color: #fff;
	font-weight: bold;
	background-color: #000;
}

And there you have it. Since I’ve yet to run into any problems with this solution, I’d recommend it over the small-height hack any day.

Did you like this? Share it:
  • Anonymous

    Thanks so much for this, I have no idea how I never knew about this until now. I consider myself to be close to an expert status on CSS, but you’re post has helped me out immensely. Thanks a trillion!!!

  • http://koviko.net/ Kovik

    It’s a shame that our expertise needs to extend to the taming of one particular browser. But, at this point, every browser has it’s own CSS flaws and none are nearly as easy to target as IE is.

    In any case, I’m glad that this has helped someone. This poor blog is soon to be demolished, so it’s good that the information made it out before then. :)

  • Test

    Thank U So much
     

  • Rex

    Excellent article, very helpful, thanks for sharing this :)

blog comments powered by Disqus