Conditional stylesheets vs CSS hacks? Answer: Neither!
From what I've seen a good number of developers these days are split between conditional stylesheets and css hacks.
You're used to seeing this:
<link rel="stylesheet" type="text/css" media="screen" href="css/style.css" /> <!--[if IE 7]><link rel="stylesheet" type="text/css" media="screen" href="css/ie7.css" />< ![endif]--> <!--[if IE 6]><link rel="stylesheet" type="text/css" media="screen" href="css/ie6.css" />< ![endif]-->
But probably also plenty of this:
div.infoBox { float: left; padding-right: 10px; _padding-right: 5px; }
CSS hacks to target specific browsers stay where the rest of your styles are, but they certainly don't validate. For sometime now, the standards community has rallied around conditional stylesheets as a solution to the validation problem.
There are a few problems with it though:
- Conditional stylesheets mean 1 or 2 additional HTTP requests to download
- As they are in the the <head>, the rendering of the page waits until they're totally loaded.
- Also - Yahoo's internal coding best practices do not recommend conditional stylesheets
- It can separate a single CSS rule into multiple files. I've spent a lot of time wondering "Where the eff is that rule coming from!?" when it turned out to be tucked away in a conditional stylesheet.
Here's my proposed solution:
<!--[if lt IE 7 ]> <body class="ie6 "> <![endif]--> <!--[if IE 7 ]> <body class="ie7 "> <![endif]--> <!--[if IE 8 ]> <body class="ie8 "> <![endif]--> <!--[if !IE]><!--> <body> <!--<![endif]-->
Using the same conditional comments, we're just conditionally adding an extra class onto the body tag. This allows us to keep our browser-specific css in the same file:
div.foo { color: inherit;} .ie6 div.foo { color: #ff8000; }
Plus it totally validates and works in all browsers.
(Hat tip to Paul Hammond and Adam McIntyre for being s-m-r-t.)
Follow me on twitter: @paul_irish
Hi. I think you're on to something… I implemented this just last month at work.
I'm doing my detection in JSTL (its on a jsp) testing against the user agent string so have it working for all browsers. Perhaps not ideal but works for the majority of users.
One of the great reasons to implement this from my perspective was the ease at which it is to decommission styles for now unsupported browsers. One simple search for .ie6 (if only!) and you're done. Plus if multiple browsers need the same fix no need to look in hundreds of places they'll all be there next to each other.
Whilst I like the idea of adding a class to the body tag as a way of separation, I don't really understand the first problem you mentioned.
The HTTP requests only occur if you're using those browsers targetted, i.e. you don't get the additional requests, if you're using firefox.
Your third point contradicts what you're saying in your post. Although it's not a conditional stylesheet per-say, you are using conditional-comments to feed conditional-css.
Surely it's better to bloat the bad browsers with a couple of requests, than it is to bloat all browsers with unused css, example.. #ie8 .something{} won't apply to firefox, but you'll have loads of these littered in your stylesheets.
Hey Mike,
True, the extra requests only go to IE.
And yes, it means extra KB on the wire for non-IE.
But on the whole, I'd think you're looking at a net gain for speed for all your users.
If I could prove this to you with numbers I'd try. :)
good idea… but this way you would invalidate your stylesheet (conditional stylesheets usually contain some hacks - e.g. zoom:1, or others.. )
reducing amount of requests is a great idea - even at the cost of bigger file size…
and then again, if you're doing optimization (sprites, minimize number of requests & gziping your css/js files), added filesize shouldn't be bigger than 1kb even for a huge site…
Hammond's post turned me on to this technique. I really like it; instead of breaking out the IE fixes into one or more extra files that I have to keep up-to-date, I just add the IE or IE6 adjustments below the relevant styles.
Interesting idea, Paul. But Mike makes some very good points in his earlier comment. What he didn't mention is that the repetition makes this solution less extensible. And what happens if someone fat fingers one of the Conditional Comments and the visiting user agent decides to march forward with the wrong BODY tag? Oh boy!
As an alternative to build on your idea, consider using script to set the value of the BODY tag's class attribute and save some repetition:
document.body.className += " ie"
Happy coding!
Not unlike http://www.nikhilk.net/BrowserSpecificCSS.aspx
Yeah definitely similar..
You can sniff on the backend, but that poses problems when it comes to caching.
You mentioned this technique on 24 ways. I think I may start using it.
I think the reduction in http requests outweighs slightly larger stylesheets for non-IE browsers, as byte for byte the size of my IE style sheets are very very small.
Why would the suggestion made by Josh cause caching issues?
Christopher,
Thanks! I think it's better to develop with, too. :)
Serverside user agent sniffing means you're delivering different pages to different people. Means more effort if you want a comprehensive caching strategy. And likely not as responsive a response.
Don't know if you were aware of this script
http://rafael.adm.br/css_browser_selector/
But you can target browsers via CSS inheritance with this script as well, but then again it's JS not a conditional comment so you're making concessions either way.
Good link, Kyle.
Yeah my optimal solution would be one that works sans-javascript. (Heh, although most of the sites I make totally require javascript)
Maybe its the anal about performance part of me. :)
Thanks for pointing that out.
Thanks so much for this helpful post!
FYI-
This is an interesting application of a similar technique, by Keenora. Probably my favorite js approach I've seen.
Yes. This is a great thing for DB's to debate while actual worthwhile software is being created.
See you in Harvard Square Paul!
This is very inspiring.
Thanks for sharing.
Works great!! Thanks mate!
Isn't CSS hacks to target specific browsers really totally obsolet? Sure thing! It's about time to force all browser creators to fully implement the W3C Recommendations. Yes, the same recommendations we use creating web contents. By publishing a totally W3C-validated work ur, of coz, done! I don't understand why we should make any effort to balance out all the browser shortcomings. These self-imposed tasks will only postpone the proper implementation of the W3C recommendations by browser creators. If I'm wrong, please correct me.
@george
and what happens when you invalidate a stylesheet? absolutely nothing. except that it "doesn't validate."
This approach is much smarter than serving multiple stylesheets.
@swed
Sure we would all like to say the heck with non standard friendly browsers, but the truth is people still use them. I was in a presentation the other day given by the CEO of my company and he presented in a webex using IE6. It was a new release and I had missed a couple IE6 tweaks but luckily they were the kind of thing only a designer would notice. The point is IE6 is not dead yet. Let us hope the day is soon.
Beautiful! Conditional comments are the safest way to go and require less page hits, but its a pain to maintain multiple sheets. With this I can keep all my css in one sheet and still have safe and accurate browser detection.
Great idea! You can get this to work in Dreamweaver by replacing the closing body tag with:
<!–[if lt IE 7 ]> </body> <![endif]–>
<!–[if IE 7 ]> </body> <![endif]–>
<!–[if IE 8 ]> </body> <![endif]–>
<!–[if !IE]>–> </body> <!–<![endif]–>
@Erin
Erin,
I have tried using your additional to get it to display correctly in DW CS4 but have been unable - any ideas?
Thanks,
Bob
I've been using this technique for a while now. Works like a charm.
I've found that I very rarely need the .IE8 selector and the .IE6/7 selectors see minimal use once you've got your head around how they work. Mind you, with 94% of my user on some form of IE, I've long since learned to code defensively anyway :)
This is an excellent idea. I'm going to implement it asap.
I agree with abomb79. No matter how much we hate IE6, it is widely used than any other browsers. I work for a big company and average of 70% of users are IE users mostly IE6. And by the way, excellent post, ideas and discussions.
And just in case you're trying to get Paul's ie-conditional-body-tag technique to work in XSLT, I've created a small code sample (which even allows you to set an additional arbitrary body class or classes):
http://gist.github.com/256183
I prefer a conditional stylesheet all of its own, and here is why… Other coders/programmers have proven that long descendent CSS selectors slow down render time of the page. So, a line for a bit of nested navigation might look like "body.ie6 #wrapper ul#nav li a { }". A long line like that slows down the page render. If it is in the main stylesheet, then ALL browsers are reading it, even if the rule wasn't meant for them.
When compared to the download time for another (hopefully short) stylesheet, I think I'd opt for the extra download time, as it is only being downloaded for IE users, so it is an extra step for one segment (albeit a large one) of the population.
By the time I am done coding a page, my stand-alone IE stylesheet needs maybe four to six rules to fix any IE-specific rendering issues. If you code defensively, and wrap things properly, and follow as many standards as possible, the difference between FF and webkit browsers vs. IE can be fairly minimal Plus, I like having all of the non-compliant/non-validating rules in one place… that way, my main screen.css will valdate just fine.