2006-07-26

:before and :after in IE7 and below

I just discovered an interesting way to get certain uses of :before and :after to work in IE7 (and somewhat in IE6 and below) with no JavaScript or extra elements required. The trick is to make use of IE's incorrect handling of comments in CSS. Using the universal selector (*), IE will treat comments as elements, although the level at which you can style them is very limited. But if you simply want it to display as a block with a certain height and a background, this trick will work.

Let's say you have a fixed-width layout and want to use background images to make rounded corners. Normally, a convenient way to do this would be to use pseudo-elements like the following:

#container:before
{
 background: url("corners-top.png");
 content: "";
 display: block;
 height: 24px;
}

#container:after
{
 background: url("corners-bottom.png");
 content: "";
 display: block;
 height: 28px;
}

Every major browser supports this level of pseudo-elements except Internet Explorer (IE7 included). Normally, you would likely resort to using empty divs instead, thus leaving an icky taste in the mouth of people who appreciate semantic markup. But with this new method, you can use markup comments instead of elements to produce the same effect. The following is how you would get it to work in IE7:

HTML fragment:

<div id="container">
 <!-- -->
 <p>Blah blah</p>
 <p>Blah blah</p>
 <p>Blah blah</p>
 <!-- -->
</div>

CSS:

#container:before
{
 background: url("corners-top.png");
 content: "";
 display: block;
 height: 24px;
}

#container:after
{
 background: url("corners-bottom.png");
 content: "";
 display: block;
 height: 28px;
}

IE-specific stylesheet:

#container>*
{
 background: url("corners-bottom.png");
 display: list-item;
 font-size: 28px;
 line-height: 28px;
 list-style: none;
}

#container>*:first-child
{
 background: url("corners-top.png");
 font-size: 24px;
 line-height: 24px;
}

/*
  Now, still in the IE-specific stylesheet, remove the styles for all
  element children of #container. Refer to each element by tag name.
*/

#container>p, #container>div, (And so on...)
{
 background: none;
 display: block;
 font-size: 1em;
 line-height: 1.25;
}

You can do some further manipulation of the comment "elements", such as giving them borders and margins, but some useful properties such as height, width, and position unfortunately don't work as expected.

Because IE6 doesn't seem to have a way to distinguish between the two comments in a single container, a little additional messiness is required. Just include the content and bottom comment in a single nested div and you can somehow work around that. Some additional caution is necessary since IE6 also doesn't support child combinators (>). Here is an example of how it might be laid out:

HTML fragment:

<div id="container">
 <!-- -->
 <div class="mainContent">
  <p>Blah blah</p>
  <p>Blah blah</p>
  <p>Blah blah</p>
  <!-- -->
 </div>
</div>

CSS:

#container:before
{
 background: url("corners-top.png");
 content: "";
 display: block;
 height: 24px;
}

#container .mainContent:after
{
 background: url("corners-bottom.png");
 content: "";
 display: block;
 height: 28px;
}

IE-specific stylesheet:

#container *
{
 background: url("corners-top.png");
 display: list-item;
 font-size: 24px;
 line-height: 24px;
 list-style: none;
}

#container .mainContent
{
 background: none;
 display: block;
 font-size: 1em;
 line-height: 1.25;
}

#container .mainContent *
{
 background: url("corners-bottom.png");
 font-size: 28px;
 line-height: 28px;
}

/*
  Now, still in the IE-specific stylesheet, remove the styles for all
  element descendants of .mainContent. Refer to each element by tag name.
*/

#container .mainContent p, #container .mainContent div, (And so on...)
{
 background: none;
 display: block;
 font-size: 1em;
 line-height: 1.25;
}

3 comments

Klaus Hartl

Truly amazing! I cannot believe this "feature" will make it into the final release...

Klaus Hartl

This technique would also make for a good clearing floats without presentational markup, as long as clear is applied.

Nanobot

I should probably mention, you could just use conditional comments instead of this weird comment hack and possibly get better results.

Post new comment

Comment moderation policy: Your comment will be reviewed before it is added to the site. This is in response to spam and other forms of abuse. I gladly accept comments containing criticism as long as the language is clean.

This weblog is powered by Blogger.