2006-04-28

Easy CSS hacks for IE7

At all costs, you should avoid hacks that rely on browser bugs, because you can bet on those bugs being fixed in some future version and thus causing problems with your code. But still, a lot of people were upset when they heard that Internet Explorer 7 was going to have the * html quirk fixed. Give us some way to detect IE7 in CSS, the people pled. Well, I certainly don't approve of using these kinds of hacks (the most appropriate way to detect Internet Explorer and specific versions thereof is to use IE conditional comments), but I happen to have discovered a few new CSS hacks that work in Internet Explorer 7 and they'll be revealed sooner or later, so I might as well spill the beans now.

Skip to "the best method"

>body

If a simple selector is missing on either side of the child combinator (>), Internet Explorer 7 incorrectly assumes that the missing simple selector is a universal selector. So >body is treated by IE7 like *>body, while other browsers ignore it because it's a parsing error. Similarly, IE7 treats >> like *>*>*.

IE7 has the same quirk with other combinators. +p is treated like *+p and ~p is treated like *~p. (Note: The ~ combinator is an upcoming CSS 3 feature and is not valid CSS 2.1.)

>body {} selects the body element in IE 7 only. It may or may not work in future versions. Warning: this uses invalid CSS!

html*

Internet Explorer 7 fixed the quirk that allowed the universal selector (*) to select some nonexistent parent of the html element, but there's another issue that they didn't fix: When a universal selector is directly adjacent to another simple selector without a space between, Internet Explorer 7 assumes a space there. That means that html* is treated by IE7 like html *, while other browsers ignore it because it's a parsing error. Similarly, IE7 treats ** like * *.

html* {} selects all descendants of the html element in IE 7 and below. It may or may not work in future versions. Warning: this uses invalid CSS!

*+html

Oh boy, doesn't this look familiar? The introduction of the adjacent sibling combinator (+) in IE7 revealed some incorrect behavior regarding the universal selector (*). It turns out that in Internet Explorer, the universal selector incorrectly selects things like comments and doctypes. We can make use of that by referring to the html element as the next sibling of the unnamed doctype "element", as Internet Explorer sees it.

*+html {} selects the html element in IE7 only. It may or may not work in future versions. This method uses perfectly valid CSS.

The best method

As I said above, the truly best method for selecting Internet Explorer or specific versions of it is to use conditional comments. However, here are the best CSS hacks to select the following combinations of Internet Explorer versions:

Update 2006-07-26: To solve some newfound issues, use *:first-child+html in place of *+html below.

IE 6 and below
Use * html {} to select the html element.
IE 7 and below
Use *+html, * html {} to select the html element.
IE 7 only
Use *+html {} to select the html element.
IE 7 and modern browsers only
Use html>body {} to select the body element.
Modern browsers only (not IE 7)
Use html>/**/body {} to select the body element.

The IE7 hacks above may or may not work in future versions of Internet Explorer. It is strongly recommended that you use conditional comments instead of the above hacks, since conditional comments are specifically features of Internet Explorer and they were designed for this purpose.

Update 2006-04-29: It should be mentioned that the current beta releases of Internet Explorer are layout complete, meaning no significant changes will be made before the final release unless there is a serious reason. Representatives from the Internet Explorer development team have also made a few mentions in the Internet Explorer feedback system that the layout engine development is currently frozen, meaning the developers aren't even touching it anymore. It's highly unlikely that any of the above will change before the final Internet Explorer 7 release.

Update 2006-07-25: A commenter noted that the *+html{} selector will also select in Opera 9 when the XML declaration is present. Opera seems to incorrectly treat recognized processing instructions (such as XML declarations) as elements with the universal selector. Due to the fact that IE6 and below fall into quirks mode when the XML declaration is present and IE7 and below don't support XHTML, you probably shouldn't be using XML declarations anyway unless you plan to go all the way and send XHTML with the correct content type (thus preventing IE7 and below from displaying your website).

If you have your mind set on sending XHTML as text/html and using an XML declaration, you can distinguish between IE7 and Opera by adding a comment before the html element. With the universal selector, IE7 will treat the comment as an element, but Opera correctly won't. Therefore, you would use *+*+html{} to just select IE7, while *+html{} would select both IE7 and Opera.

Update 2006-07-26: A better hack for IE7, which solves both the issue with Opera/XHTML and IE 5/Mac, is *:first-child+html {}. It doesn't require the comment or any other additional markup (in fact, the presence of a comment would require additional modifications to the selector).

22 comments

Anonymous

Great!

Sander

I disagree with conditional comments being the most approriate way - they reek of useragent detection to me, while (syntactically valid) CSS hacks at least are based on capability.

That said, great research! I very much suspect (and regret) that *+html will come in very handy indeed.

Nanobot

Offering code/instructions/rules based on capability is very desireable, but that often isn't possible in CSS when the browser supports something but supports it incorrectly.

Hacks like *+html{} do not serve up code based on feature support, because how a browser handles the universal selector has nothing to do with how it handles floats and margins. So you're detecting one feature and making assumptions about other feaures because of knowledge about the specific user agents. It's basically user agent sniffing, but worse and more problematic.

IE conditional comments are a form of user agent sniffing, yes, but it's *reliable* user agent sniffing, which gives it the edge over selector hacks.

Sander

It's only reliable user-agent sniffing until enough clueless webdevelopers start abusing it to send essential styling IE's way, and none to other browsers, after which minority browsers will have no choice but to start interpreting it as well. We've been down that road before.
In this modern world, that doesn't seem very likely to happen, but if there's anything the browser wars have taught us, it's that things that seem unlikely can happen very swiftly.

In that scenario, CSS hacks have the benefit of being far more granular, and the good ones of obviously working negatively ("this _shouldn't_ work; and I'm working around a single and specific bug here"), while conditional comments make it too easy to paint with a broad brush, inviting the approach of "one stylesheet for IE, one stylesheet for Firefox, and tough luck for everything else, because no one seriously uses other browsers anyway, right?". We want to avoid promoting mindsets in which browser-specific /anything/ plays a role.
(And yes, there'll be some people over-abusing CSS hacks and painting with the same brush, but (IMO) their very nature makes that far less likely.)

Fair point on selector capabilities not saying much about other capabilities, but when you're using a "this should be ignored" wrapped around a "this shouldn't make any discernible difference" (both parts of the hack being essentially harmless), I've found it a safe bet to make assumptions on how they're tied together anyway. And indeed, 99% of the * html uses in my websites can remain as they are. :)

Nanobot

Okay, I see your point. I disagree with your final conclusion and I don't see IE comments being abused in the way you describe, but you do seem to have a valid argument. The bottom line is that all hacks and browser sniffing come with risks, and those risks should be weighed carefully before deciding how to solve a given problem.

Adam Messinger

These could actually be incredibly useful when combined with conditional comments. Right now I've got two seperate IE-only stylesheets -- one for IE7 and one for IE6 and lower.

Using the *+html hack, however, I can roll these together into one sheet that's delivered to IE7 and below. Thanks!

Maujor

Hi David,
Congrats. Very interesting article.
I request your permission to translate to brazilian portuguese and share it with my visitors.
Maurício Samy Silva
Maujor's Blog

Nanobot

Maujor: Sure thing. :)

Maujor

Hi David,
Brazilian portuguese translation is alive at:
Hacks CSS para o IE7

David Fox

I too have to disagree with the comment that conditional statements are the way to go. I find them difficult to keep track of but I guess it's also a personal preference too.

As for people not wanting to use certain hacks because the CSS won't validate, I do agree but I think when any commercial sites we've made suddenly break and our clients start yelling down the phones at us, we'll do anything to get them fixed!

Nanobot

Adam Messinger's suggestion sounds like a pretty reasonable middle ground. There are problems with CSS hacks as far as the unexpectedness of future browser development (within familiar browsers as well as any newcoming browsers), but if you limit the exposure of those hacks to one rendering engine through a simple IE conditional comment, you can use CSS hacks within that IE-specific stylesheet to better handle the different versions. That way, the only layout engine at risk of being inadvertently affected by the hacks is Trident (Internet Explorer), and then the risks of changes in future versions remains more or less the same. That is, among the decisions to also send IE7-specific CSS to IE8 and up, to send no special CSS to IE8 and up, or to use a hack that may or may not send the IE7-specific CSS to IE8 and up, it's more or less a toss-up as far as the risk goes. The likelihood of needing to go back and fix it up for the next version is arguably about the same at that point.

Still, I think it's important that you're certain you're only dealing with Internet Explorer bugs when you use these hacks, and the only reliable way to do that is to use IE conditional comments for at least once IE-specific stylesheet. Otherwise, you might at some point run into some other user agent that happens to stumble on your hack.

Darren (xyhfna) Robinson

i have a small addition to what has been said... IE style conditional comments have a couple of plus and minus points.

negatives:
1) conditional comments are by essence an abuse of the commenting system, more appropriate mechanisms should be implemented (regardless of language - see below)

2) conditional comments the MSIE way are dependent on a common HTML document, so requiring different dependent documents (stylesheets in this instance) to be served. if conditional comments were implemented in the dependent document, then the common documents (HTML) could be ignorant of implimentations within the dependent documents. and could be universally applied to all common documents with one alteration cascading all of them as is the case with css hacks.

3) conditional comments the MSIE way does nothing to solve the problems of other browser inconsistancies. we still end up relying on hacks for opera, safari, mozilla, netscape, etc.

positives:
1) a simple and effective way to deal with incarnations of IE, its features and bugs.

2) in principle a universally accesible mechanism (see above for appropriateness) for filtering content for ALL browsers, if other developers begin to support it, and gracefull failure if not.

3) As i hinted at in comment above, its usefullness applies to alsorts of content not just dependent documents!

PS:
in addition to the MSIE debate, we have to recognise that the only way to handle layout bugs, etc is to know the bugs for each useragent and use ua detection to deliver content, altered in varying degrees from the STANDARD model. unfortunatly for us the only ways to do this are rather hit and miss with javascript ua detection (object detection in this cas would not solve our problem as it tells us nothing about the layout peculiarities), or MSIE proprietory (but guarenteed detection) conditional comments.

My opinion, conditional comments (or a more appropriate alternative) should be available in HTML through all platforms not just IE. css should have features to ensure ua detection is possible (without js or html cc), and browsers should not attempt to circumvent ua detection (which has been a growing problem for all). Hacks could then be finally layed to rest once and for all.

Other than that, a great article :-)

Anonymous

There is a bigger issue going on... dealing with the powers that be. CSS hacks have essentially performed as makeshift CSS conditional statements. Why? Because the powers that be have stated that CSS cannot contain conditional statements. Browser makers should comply to the CSS standards and act accordingly.

Well, whether on purpose or on accident... the reality is that there will always be some issues. So now we will enter into a new era of browser wars, waged on the CSS battlefront rather than the HTML. Designers won't be sniffing out useragents to deliver one HTML page or another, now it will be to deliver one of X CSS files... different CSS for IE, perhaps some for the rest of the world, printer version, wireless, etc.

If the goal of CSS was to remove layout from content and to help yield a more accessible and consistent design, seems like we are about to trip. CSS is just developed and deployed... it is tweaked here and there over time. Trying to maintain consistency across X style sheets will become a nightmare... and resorting to hacks again to reduce the number of CSS's to maintain will become the norm.

When you make the rules, who says something can't be. Give us CSS conditionals and lets all work for the greater good.

Vasil Dinkov

*+html {}

also targets IE5/Mac and MSN/OSX. Yeah, I know they are pretty rare browsers nowadays (especially MSN) but here's an easy fix I found anyway:

*+html {} /* for in IE7 */
:root {} /* put the default value here */

IE7 doesn't support the :root pseudo-class.

Anonymous

Please mind that *+html also targets Opera, at least version 9 under Linux. Vasil's patch doesn't fix this either.

Nanobot

*+html{} doesn't select anything for me in Opera 9 on Linux. Could you provide a test case?

Anonymous

Opera seems to interprete the XML header as an own HTML element, as you can see in
this testcase (screenshot).
This also happens in XHTML mode, as you can see here.

If you use *+*+html, Opera shows the paragraph blue, but I don't know if this still works in IE7.

Alex Robinson

As Vasil Dinkov noted *+html also targets IE5/Mac, so the statement in the article that it's IE7 alone is misleading (notwithstanding the Op9 xml prolog issue)

Yes, it's easy to hack around using Vasil's :root suggestion or escaped comments (/*\*/ ... /**/), but it should be mentioned.

MEMark

It appears that using
*+html, * html {}
combined to serve properties to IE 7 and below does not work. IE 6 seems to ignore any rule containing the sibling selector (+). Can somebody confirm this?

MEMark

As you probably know, the commonly used underscore hack can no longer be used in IE 7. But starting out from this page
http://annevankesteren.nl/2005/07/ie-hack

I found that the following characters are still usable as prefixes in both IE 6 and 7.
!@#$%^&*()-=/?.,|[]{;:<>

I have not tested in other browser, though I'd assume they correctly ignore these non-existing properties.

Nanobot

The *+html, * html {} hack takes into account IE6's lack of support for the + combinator. The first part of the selector (*+html) attempts to target only Internet Explorer 7, while the second part (* html) attempts to target IE6 and below. The rest of the desire selector (#id .class or whatever) is added to both parts, meaning you end up with something like *+html #id .class, * html #id .class {}.

The point of the underscore hack was that the CSS specification has special provisions for properties starting with an underscore (_) or hyphen (-). These are reserved as vendor-specific properties and are guaranteed not to be used in any future CSS standard. That made those prefixes inherently safer to use for vendor-specific purposes such as IE hacks than other symbols which are considered "more invalid".

IE7 fixes the "_" and "-" prefixes. You can still use an asterisk (*) as a prefix for targetting IE7 and below, but it's best to avoid invalid CSS if possible.

librarianne

saw a comment of yours on another site. I just wanted to say THANK YOU!

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.