Using CSS3 in the workplace with minimal trouble & strife
About this article
Web Designer Magazine approached me to write a CSS3 article back in February 2011. Having spent the last few days making a client’s site looking good in IE6, I thought this would make for a good article. You can download the files for this tutorial here (920k zip file).
Introduction
You’ve no doubt read a lot of articles about CSS3, so you know how it can help you to perform miracles and probably improve your love life (or is that HTML5?). You may also have read that you can forget about those older browsers and “live in the now”. Some people even seem to design only for WebKit-based browsers. Yay for fantasy worlds!
But, lots of us still work in the real world–a world where our Enterprise clients still rely heavily on archaic technologies, such as IE6 and it’s evil twin brothers, IE7 & IE8. Should you still be serving up those gradients and rounded corners as images for such lesser browsers? Hell no!
In this article, you’ll learn how to serve up a site that looks the same in all browsers; from the latest Chrome and Safari all the way down to IE6, complete with all those CSS3 treats, media queries, and some CSS2.1 selectors. You’ll also learn to climb out of any holes along the way.
With some conditional comments, a couple of small JavaScript libraries and a text editor, you’ll be keeping everyone sweet, no matter which browser they’re using–all with minimal trouble and strife.
Step 1: Let’s get started
Open up index.html and we’ll focus on the
first. You’ll see we’re using a reset stylesheet and then setting some default styles. This is going to help to get everything playing nicely across the different browsers; the fewer browser oddities, the better. We’re using s rather than lazy @imports.<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS3 Enterprise—Using CSS3 in the workplace with minmal trouble & strife</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="css/html5reset-1.6.1.css" media="screen" />
<link rel="stylesheet" href="css/default.css" media="screen" />
<link rel="stylesheet" href="css/css3enterprise.css" media="screen" />
Step 2: Conditional Comments
If you’re new to conditional comments, they’re the best way to serve up IE-specific content without resorting to ugly hacks. What you have here are rules to serve up stylesheets like so: everything below IE9, 7+, 8, 7- and finally IE6. There’s also @rem’s HTML5 shiv in there, to stop elements falling all over the screen in IE.
<!--[if lte IE 8]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<link rel="stylesheet" href="css/ie.css" media="screen" />
<link rel="stylesheet" href="css/pie.css" media="screen">
<![endif]-->
<!--[if gte IE 7]>
<link rel="stylesheet" href="css/pie78.css" media="screen" />
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" href="css/ie8.css" media="screen" />
<![endif]-->
<!--[if lte IE 7]>
<link rel="stylesheet" href="css/ie7.css" media="screen" />
<![endif]-->
<!--[if lte IE 6]>
<link rel="stylesheet" href="css/ie6.css" media="screen" />
<![endif]-->
</head>

Step 3: JavaScript assistance
Okay, moving down to the bottom of the page, you’ll find some JavaScript files lurking in conditional comments as well. These have become known as polyfills and further help to fill the holes in IE6-8. You’ve got one to add some missing selectors and one to add the power to use media queries. The last one adds some more selectors.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script src="js/functions.js"></script>
<!--[if lte IE 8]>
<script src="js/selectivizr.js"></script>
<script src="js/css3-mediaqueries.js"></script>
<![endif]-->
<!--[if lte IE 6]>
<script src="js/ie6.js"></script>
<![endif]-->
</body>
</html>
Step 4: Grab a slice of PIE
The main focus of this article is on a nice little behavior file called PIE: Progressive Internet Explorer (css3pie.com). PIE does for CSS3 what ibuprofen does for headaches–it relieves the pain. Now you have border-radius, box-shadow, gradients and transparent PNGs, all in one tidy file. Let’s investigate a slice of PIE served on the site.
#site-header {
background-color: #000;
background: -webkit-gradient(linear, left top, left bottom, from(#4b4b4b), to(#000));
background: -moz-linear-gradient(top, #4b4b4b, #000);
-moz-border-radius: 8px 8px 0 0;
-webkit-border-radius: 8px 8px 0 0;
border-radius: 8px 8px 0 0;
color: #fff;
overflow: hidden;
position: relative;
/* add the PIE magic -- */
behavior: url(/css3pie/PIE.htc);
}
Step 5: Serve your PIE correctly
Chances are your web server is already configured to serve up PIE with the correct content-type (text/x-component). If you can’t get it working, it’s possible that it’s being served incorrectly. You can work around this with some .htaccess action, or by using the PHP script which is included. So, to use the PHP version, you just change three letters.
#site-header {
background-color: #000;
background: -webkit-gradient(linear, left top, left bottom, from(#4b4b4b), to(#000));
background: -moz-linear-gradient(top, #4b4b4b, #000);
-moz-border-radius: 8px 8px 0 0;
-webkit-border-radius: 8px 8px 0 0;
border-radius: 8px 8px 0 0;
color: #fff;
overflow: hidden;
position: relative;
/* add the PIE magic -- */
behavior: url(/css3pie/PIE.php);
}
Step 6: Serve your PIE correctly
You may come across an instance where the page has fully loaded, but you’re going to introduce new elements that you need to PIE. If you think it’s all over, there’s still an option to try: PIE.js. Throw a callback to PIE.js in the mix and you’ve still got control.
<script src="/css3pie/PIE.js"></script>
$(function(){
if ($('.post-DOM-element').length) {
$('.post-DOM-element').each(function() {
PIE.attach(this);
});
}
});
Step 7: Keep things neat and tidy
As you can see, using PIE is as easy as adding a behavior file into your CSS declarations. We don’t want to go throwing it all over the place, though. We’ll use a separate stylesheet to keep things neat and tidy, using the same commented sections as the main stylesheet for ease of use.
/*
SITE: CSS3 Enterprise
FILE: pie.css
GEEK: @philsherry
DATE: 2011-02-22
WHAT: css3pie styles for IE6-8
Copyright ©2011 Phil Sherry. All rights reserved.
*/
/* declare all the elements which need to be PIE'd */
/* -- default -------------------------------------------------------------- */
/* -- layout --------------------------------------------------------------- */
/* -- lists ---------------------------------------------------------------- */
/* -- forms ---------------------------------------------------------------- */
/* -- gradients ------------------------------------------------------------ */
/* ------------ black -- */
/* ------------ green -- */
/* ------------ white -- */
/* ------------ orange -- */
Step 8: Rounded corners
In the last few years, pretty much everything has had rounded corners. Mainly because… well, because we can now. You can retire that jQuery snippet for added them to IE, because PIE is all you need to get the job done. It uses the same syntax and couldn’t be easier to use. Let’s look at adding some curves to the top of that site header.
/* for decent browsers */
#site-header {
/* gecko browsers */
-moz-border-radius: 8px 8px 0 0;
/* webkit browsers */
-webkit-border-radius: 8px 8px 0 0;
/* non-prefixed rule */
border-radius: 8px 8px 0 0;
}
/* for IE6-8 */
#site-header {
/* add the PIE magic -- */
behavior: url(/css3pie/PIE.htc);
/* this will use the non-prefixed rule from above */
}
Step 9: Easier gradients
Ditching gradient images for CSS gradients is fantastic. No more slicing up images and having to redo them when a client changes the color scheme. You have that same freedom with IE now. The rule is the same across the board, since a new change in how WebKit handles things. Let’s get a gradient in that header.
#site-header {
behavior: url(/css3pie/PIE.htc);
/* old WebKit syntax */
background: -webkit-gradient(linear, left top, left bottom, from(#4b4b4b), to(#000));
/* new WebKit syntax */
background: -webkit-linear-gradient(top, #4b4b4b, #000);
background: -moz-linear-gradient(top, #4b4b4b, #000);
/* PIE style */
-pie-background: linear-gradient(top, #4b4b4b, #000);
}
Step 10: Rounded corners and gradients
One really nice reason for using PIE is saying goodbye to those ugly IE filters for gradients. In fact, you’ll benefit in another way when you want to use them in conjunction with rounded corners. If you try to use a filter with a rounded corner, you’ll see a lovely square corner. Bleh, gimme PIE!
#site-header {
/* old, ugly, hacky way */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#4b4b4b, endColorstr=#000);
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4b4b4b, endColorstr=#000)";
/* when come back, bring PIE */
behavior: url(/css3pie/PIE.htc);
background: -moz-linear-gradient(top, #4b4b4b, #000);
}
Step 11: PNG transparency
Using transparent PNGs in IE has always been a bit painful, but the latest version of PIE handles them like a champ–even on background images. So, no more serving up both 32-bit & 8-PNGs and losing loads of quality with the latter. As is the PIE way, it’s dead easy to add transparency to your PNGs in IE.
img {
behavior: url(/css3pie/PIE.htc);
-pie-png-fix: true;
}
Step 12: Embrace the alpha channel
While you’re still feeling all warm and fuzzy from seeing those transparent PNGs working nice and easily with PIE, there’s more. If you’ve been using rbga() at all, you’ll be glad to know this is supported with PIE as well. Yes, you can use that alpha channel with another slice of PIE, just the same as you would in your regular stylesheet.
#kitten .title {
-pie-background: rgba(0,0,0,.5);
}

Step 13: Lazy loading
As with real pie, too much PIE can make you fat. If you’ve got a really big page with tons of elements that need to be PIE’d, you might notice you hit a speed bump as the page loads. No surprise there, but you can smooth that out with some lazy loading.
.pie-rules {
behavior: url(/css3pie/PIE.htc);
-pie-lazy-init: true;
}
Step 14: It’s all relative
As amazing as PIE is, you may find a few gotchas. Luckily, they’re easy enough to deal with. One of the old IE standby fixes is built into PIE: zoom:1. Something you’ll have to add more than a few times is position:relative. So, you might want to just beef up your PIE rule to include that by default and override when needed.
.pie-rules {
behavior: url(/css3pie/PIE.htc);
-pie-lazy-init: true;
-pie-png-fix: true;
position: relative;
}
#positioned-element {
/* this element needs PIE but is positioned absolutely
so reset the position here */
position: absolute;
}
Step 15: Another relative point
Another important point to note when adding your PIE behavior, is how to target the file. Because of the way IE parses the behavior file relative to the actual HTML file that it’s being used against, you must specify the location of PIE as such. Using an absolute path is the path of least resistance.
/* absolute: gooood */
.pie-rules {
behavior: url(/css3pie/PIE.php);
}
/* relative: baaaad */
.pie-rules {
behavior: url(../css3pie/PIE.php);
}
Step 16: PIE’s Pernickety Percentages
Another bug to be aware of in the current version of PIE seems to happen when you use a percentage value to pad an element. You get a lovely dialogue window in IE, telling you the sky is falling and asking if you want to debug it. No need for that: just specify the values in pixels, job’s a good’un.
legend {
border: 3px solid #2f6d7a;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 5px 10px;
/* PIE gotcha:
using a percentage value here will give you a nice error
eg: padding: 2% 5%;
-- */
}
Step 17: Shorthand is a must
If you’ve been writing CSS for a while, you’ll probably be familiar with CSS shorthand. This is good; because it means you probably have a better understanding of what you’re doing. But also, while PIE is just dandy with shorthand values, it doesn’t like longhand values and won’t work if you try using them.
/* shorthand: gooood */
#user-nav {
-moz-border-radius: 0 8px 0 8px;
-webkit-border-radius: 0 8px 0 8px;
border-radius: 0 8px 0 8px;
}
/* longhand: baaaad */
#user-nav {
-webkit-border-top-right-radius: 8px;
-webkit-border-bottom-left-radius: 8px;
-moz-border-radius-topright: 8px;
-moz-border-radius-bottomleft: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
}
Step 18: Selectors via selectivizr
Okay, that’s enough with the PIE show already. We’ll cover some slightly older (CSS 2.1) selectors now. Why? Because they’re still awesome, and yet they’re still missing in IE6-8. With all kinds of small JavaScript libraries available these days, naturally, there’s one that replaces many of these selectors. We’ve used selectivizr.js in our demo site, and with that, we get [attr] selectors.
/* fully valid URL, likely external link */
a[href^="http://"] { background-image: url(../images/external.png); }
/* internal relative link */
a[href^="/"], a[href^=".."] {}
/* email link */
a[href^="mailto:"] { background-image: url(../images/email.png); }
/* PDF file */
a[href$=".pdf"] { background-image: url(../images/page_white_acrobat.png); }
/* Microsoft Word file */
a[href$=".doc"] { background-image: url(../images/page_white_word.png); }
/* music file */
a[href$=".mp3"] { background-image: url(../images/page_white_cd.png); }
/* archive file */
a[href$=".zip"] { background-image: url(../images/page_white_compressed.png); }
a[href^="http://"],
a[href^="mailto:"],
a[href$=".pdf"],
a[href$=".doc"],
a[href$=".mp3"],
a[href$=".zip"] {
background-repeat: no-repeat;
background-position: 98.5% 50%;
padding-right: 20px;
/* cross-browser inline-block: http://foohack.com/2007/11/cross-browser-support-for-inline-block-styling/ */
display: -moz-inline-stack;
display: inline-block;
zoom: 1;
*display: inline;
}
Step 19: No child left behind
A really handy selector from the CSS3 stable is :last-child. In our demo site, we’ve used that to position one of the links away from the main links and style it slightly differently. As with lots of good stuff, this is missing in IE6-8, but selectivizr fills that gap and adds it right in there.
#site-nav li:last-child { margin-left: 250px; }
Step 20: Selectors via jQuery
Unfortunately, selectivizr doesn’t cure all ills, so you can’t relax just yet. If you really do want to use the same selectors throughout your site, you can get jQuery to do some of the heavy lifting. If you’re after using the > selector, then it’s easy enough. Just add a couple of lines to your ie6.js file, like this.
$(document).ready(function() {
$("section > h1").css('font-size','42px');
$("article > h1").css('font-size','24px');
});
Step 21: Media Queries
Unless you’ve been living under a rock for the past few months, you’ll no doubt have heard all about media queries and responsive web design. Anyone with an iPhone, iPad or smartphone can now get served up the same site in different sizes, dependent on the size of the viewport. Pretty nifty stuff. Andy Clark has kindly provided a nice boilerplate to use.
/*
Hardboiled CSS3 Media Queries by Andy Clarke:
http://stuffandnonsense.co.uk/blog/about/hardboiled_css3_media_queries/
Author: Andy Clarke
Web site: http://stuffandnonsense.co.uk
Twitter: http://twitter.com/malarkey
Hardboiled Web Design
Web site: http://hardboiledwebdesign.com
Twitter: http://twitter.com/itshardboiled
Version date : 30th September 2010
Version: 0.9
License: Creative Commons CC Zero Declaration. No Rights Reserved.
*/
/* Smartphones (portrait and landscape) ----------- */
@media only screen and (min-device-width : 320px) and (max-device-width : 480px) {
/* Styles */
}
/* Smartphones (landscape) ----------- */
@media only screen and (min-width : 321px) {
/* Styles */
}
/* Smartphones (portrait) ----------- */
@media only screen and (max-width : 320px) {
/* Styles */
}
/* iPads (portrait and landscape) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) {
/* Styles */
}
/* iPads (landscape) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) {
/* Styles */
}
/* iPads (portrait) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) {
/* Styles */
}
/* Desktops and laptops ----------- */
@media only screen and (min-width : 1224px) {
/* Styles */
}
/* Large screens ----------- */
@media only screen and (min-width : 1824px) {
/* Styles */
}
/* iPhone 4 and high pixel ratio devices ----------- */
@media
only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5) {
/* Styles */
}
In Detail: Beating IE6-8 into responsive submission
One of the latest hot topics is responsive web design. This boils down to serving up a site, but with CSS that adapts itself to the viewport of whichever device you’re using. This is done with some magic called media queries. They look a little scary at first, but they’re pretty easy to get your head around. Internet Explorer, on the other hand, doesn’t understand them at all. As ever, the internet’s favourite ginger-haired cousin needs a stern word. Once you’ve added a small JavaScript file, we’re using css3-mediaqueries.js here; you can then set about declaring different rules for different browser viewports. And just as an added extra, PIE works really nicely when the browser is resized. So, you get the full experience in IE at any size you like.
Step 22: Media Queries in IE
However, as you might expect, what with such an awesome feature, it’s not supported natively in IE6-8. As you’re probably beginning to learn, that no longer means you have to miss out, as there are some small libraries you can use to add this functionality to IE. We’re using css3-mediaqueries.js here, which works great.
/* -- Desktops and laptops -- */
@media only screen and (min-width : 1224px) {
#page {
width: 1200px;
}
#site-search .text {
margin: 0;
width: 195px;
}
#content-main { width: 800px; }
#content-sub { width: 300px; }
#footer-icons li { padding: 5px 10px; }
}
This article is copyright © 2012 Phil Sherry.
Tweet