Nothing drives me to drinking like browser testing a website on Internet Explorer 8 and below. Thankfully, I’ve found a couple of techniques that take the edge off and make the process a lot more fun.

OK, maybe not fun. But at least a heck of a lot easier and without the hangover.

The Problem

If you use a popular CSS framework like Foundation or Bootstrap, then chances are your site doesn’t support IE8 and below. For some of you, that may not be an issue because no one visits your site on those browsers. that’s the case for my personal site, but it wasn’t for a recent client I worked with. My suggestion is to consult your analytics (you are collecting data, right?!) and determine if supporting optimizing for IE is worth your while.

The problem with IE8- is that it conflicts with today’s best practices for coding responsive websites. We’re taught that developing for mobile first with progressive enhancement for larger screens is the gold standard. But IE8- completely ignores media queries, so the only CSS it recognizes are the ones that we write for small screens. At best your carefully crafted code looks like a giant mobile site. At worst, your styles and content source ordering are completely out of place.

Create Separate Stylesheets

Nicolas Gallagher has already provided a wonderful and extensive explanation on this, but the general idea is to create two separate stylesheets:

  • main.css, which targets standard browsers
  • iesucks.css, which targets IE8 and below

Here is how we link them up in our HTML:

<link rel="stylesheet" href="/css/main.css" media="(min-width:320px)">

<!--[if (lt IE 9) & (!IEMobile)]>
  <link rel="stylesheet" href="/css/iesucks.css">
<![endif]-->

The first line links up our primary stylesheet. The second links up our IE styles and is wrapped in a conditional statement that tells the browser to download them only if it is a browser that is less than IE9.

Why isn’t the first stylesheet wrapped in a conditional statement? It includes the media attribute which IE8- won’t recognize. You can read Nicolas Gallagher’s post if you want the full explanation.

Compiling Our Styles With SASS

Sure, this is a great way to target legacy IE browsers but who wants to maintain two separate stylesheets? Think about having to make the same change twice every time you need to edit a stylesheet. I’ve heard that insanity is making the same mistake over and over again, so this could be your ticket to crazy town if you want to go there.

Enter SASS! We can create multiple stylesheets from the same set of code if we set things up correctly, so let’s start there.

Let’s create two folders: one that holds our SASS files and another that will hold our CSS files when they are compiled. That would look like this:

project
├── css
└── scss
    ├── iesucks.scss
    ├── main.scss
    ├── _functions.scss
    └── _module.scss

The first two files

Both iesucks.scss and main.scss will import the exact same files as one another, but they will compile into the separate stylesheets we need to target our different browsers.

For our main stylesheet:

// Configurable variables
$old-ie: false;
$px-only: false;

// Import SASS functions
@import "_functions.scss";

// Import SASS styles
@import "_module.scss";

And for our IE-only stylesheet:

// Configurable variables
$old-ie: true;
$px-only: true;

// Import SASS functions
@import "_functions.scss";

// Import SASS styles
@import "_module.scss";

They look pretty similar right? The only difference are the true and false variables at the top of each file. We’ll address those next.

Define our SASS functions

There are two primary pain points when it comes to dealing with legacy versions of IE. The first is that they don’t recognize relative units like em and rem. The second is that they ignore media queries. The goal is to serve relative units and media queries to the main stylesheet and our fallbacks to the IE stylesheet. Let’s go over two SASS functions/mixins that help us do that.

The first is converting relative units into pixels. There are a freaking ton of resources online that will help you write a SASS mixin that does this. The majority of them though do it in a way that serves both the relative units and the fallbacks to the same stylesheet which is neither maintainable or efficient.

Sébastien Axinté came up with a beautiful solution for this and wrote it up on David Walsh’s awesome blog.

So, let’s add this to our _functions.scss file:

$pixelBase : 16;

@function parseInt($n) {
	@return $n / ($n * 0 + 1);
}

@function u($values){

      $list: ();

      @each $value in $values {

            $unit : unit($value);
            $val  : parseInt($value);

            @if ($px-only) and ($unit == 'rem') {
                  $list: append($list, ($val * $pixelBase) + px);
            }

            @else if($unit == 'px') or ($unit == 'rem'){
                  $list: append($list, $value);
            }

            @else {
                  @warn 'There is no unit conversion for #{$unit}';
            }

      }

      @return $list();

}

I highly encourage you to read the full post on David Walsh’s blog to get the full explanation for how this works because it’s genius. In short, we create a mixin that accepts any relative unit, converts it to pixels, then serves the right unit to the right stylesheet as defined by the $px-only variable.

So, now we can write our units like this:

.module {
  margin: u(1rem);
}

…which output this in our main stylesheet:

.module {
  margin: 1rem;
}

…and like this in our IE stylesheet:

.module {
  margin: 16px;
}

The second SASS function we need is what allows us to write legacy IE-only styles next to our main styles without them mixing together in the output CSS.

Jake Archilbald wrote a clean mixin that does exactly that, so let’s add it to our _functions.scss file.

$old-ie: false !default;

@mixin old-ie {
    // Only use this content if we're dealing with old IE
    @if $old-ie {
        @content;
    }
}

The same principle from our first mixin is also working in this one: if this variable is set to true, then include the things happening in this function. If the variable is set to false (which it is by default), then ignore the following stuff.

That means that like this:

.module {
  float: left;
  @include old-ie {
    float: right;
  }
}

…will float our module to the left in our main stylesheet and to the right for our iesucks stylesheet.

Writing Our Styles

Finally, we can start writing some styles! Open up your _module.scss file and start hacking away. Now, we can write something like this:

.module {
  float: left;
  position: relative;
  width: u(32px);
  @include old-ie {
    background: #000;
  }
}

…will output like this in our main stylesheet:

.module {
  float: left;
  position: relative;
  width: 2rem;
}

…and like this in our iesucks stylesheet:

.module {
  float: left;
  position: relative;
  width: 32px;
  background: #000;
}

Pretty awesome, right? We are writing styles for two separate stylesheets from one element.

Pros and Cons

Everything has its advantages and disadvantages. While these techniques are solid, they do come with some potential costs that you’ll have to weigh as you start your project.

Pros

  • Compile once and your done
  • Smaller file sizes
  • Fewer files to manage

Cons

  • Potentially cluttered code
  • Relies on a hack in the HTML

Additional Resources

SASS

  • bob

    This looks like a solid approach, I will definitely be trying it. Thanks!

  • Is there a way for the IE only mixin to output the styles only needed for IE?

    I’ve been using Jake Archibald’s IE mixin but this outputs the lines of CSS that would be included in the main css file too. Excluding the non-IE styles output by the mixin.

Subscribe to Devigner Digest

I read a lot of crap about design and development and 90% really is crap. Subscribe and I will send links to the other 10% about once a month.