What's going on here?

Building CSS mobile-first is the way forward, because blah blah blah progressive enhancement blah. Problem is, Internet Explorer prior to 9 ignores anything within media query blocks, leaving those browsers with mobile styles.

Not all of us can get away with that, but thankfully, as Chris Eppstein points out, Sass 3.2+ can be used to generate a separate stylesheet with everything it needs to create a "desktop" look.

This page was built mobile-first where smaller width devices get a single column layout, but IE8 and below still get a two column layout. The code is on github, but read on for a brief explanation.

If you prefer to use Less, Colin Bacon details a similar approach.


This file controls the page layout:

.page {
    max-width: 70em;
    margin: 0 auto;
.content-margins {
    margin: 10px;

    @include respond-min(60em) {
        margin: 20px;
    @include respond-min(75em) {
        margin: 40px;
.primary {
    @include respond-min(45em) {
        float: left;
        width: 70%;

        @include old-ie {
            // These hacks won't appear in the normal stylesheet
            display: inline;
            zoom: 1;
            whatever-ie-needs: le-sigh;

        & .content-margins {
            margin-right: 30px;
.secondary {
    @include respond-min(45em) {
        float: left;
        width: 30%;

As you can see, there are some special blocks for doing responsive stuff, along with some IE specific stuff. These are user-defined mixins, defined in...


$fix-mqs: false !default;

@mixin respond-min($width) {
    // If we're outputting for a fixed media query set...
    @if $fix-mqs {
        // ...and if we should apply these rules...
        @if $fix-mqs >= $width {
            // ...output the content the user gave us.
    @else {
        // Otherwise, output it using a regular media query
        @media screen and (min-width: $width) {
// I also have a respond-max mixin, that does what you might expect

$old-ie: false !default;

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


This simply brings all the includes together.

@import 'utils';
@import 'global';
@import 'layout';


This generates the IE<9 stylesheet:

$old-ie: true;
$fix-mqs: 65em;
@import 'all';

Here we set the width we want our media queries to be flattened for. In this case, we want to act like the document is 65em wide. This means our media queries for greater-than 45em & 60em apply, but the one for 75em is simply discarded.

Including the CSS

To give the right CSS to the right browsers, we use good old conditional comments:

<!--[if lte IE 8]>
    <link rel="stylesheet" href="css/all-old-ie.css">
<!--[if gt IE 8]><!-->
    <link rel="stylesheet" href="css/all.css">

Other solutions

There are other ways to cater for IE that don't depend on Sass, such as this (documented by Jeremy Keith) and respond.js.

Jeremy's method works but depends on you putting your responsive stuff in a separate file. Personally I find that putting overrides far away from the thing it's overriding makes it difficult to maintain, which is also why I'm against separately-maintained CSS files for IE hacks.

respond.js is obviously JavaScript dependant, and requires you to host the CSS on the same server as the page, meaning you can't use a performance enhancing CDN. Also, I hear it's a little slow, which JS-CSS crawlers generally are, but I don't have any evidence particular to respond.js.

Won't this bloat my CSS?

Each call to respond-min/max will result in an @media block in your CSS, whereas you may optimise this to one block per breakpoint if you were hand-writing your CSS.

In that case, the Sass output will indeed be larger than hand-written CSS, but gzip will chew through the repetition making the difference negligible. Also, the Sass community is looking into ways around the repetition.

So, there you go!

Some dummy secondary content

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus venenatis orci eget nisl luctus et luctus diam interdum. Etiam porttitor tincidunt erat, ac lacinia nibh lacinia sed.

Pellentesque tincidunt consectetur dolor, nec facilisis mi dapibus eu. Duis urna dui, fermentum dictum varius ut, ullamcorper eget augue.

Nulla laoreet lacinia lorem eu adipiscing. Sed commodo blandit sapien sit amet dictum. Sed suscipit, massa non ornare congue, nisl neque rhoncus turpis, facilisis elementum ligula lorem eget ligula.

Maecenas posuere mi eget justo ornare nec pretium velit consectetur. Mauris nec risus augue. Suspendisse sed libero eros, hendrerit dignissim magna. Quisque tortor neque, mollis congue aliquet vitae, pharetra non massa.

Praesent sed mauris ut sapien ultricies tincidunt a in turpis.