Over the course of this year, we've been asked quite a few times how we structure our CSS for responsive projects. For most of 2012 we've been using a system that allows us to serve a responsive experience to user agents that support media features and a non-responsive, larger experience ("desktop," if you like) to user agents that don't support media features (primarily IE8 and older).
To achieve this, we've used SCSS aggregates that contained media queries and SCSS partials for each breakpoint that had no media queries. This allowed us to create two aggregate files — one with media queries (mq.scss) and one without (nomq.scss). These two aggregates would perform a SCSS @import on all the same breakpoint-based partials (e.g. _30em.scss or _600px.scss). In the head of the document, we have then linked to the mq.css file for all user agents and the nomq.css file inside a conditional comment for older IE. See Nicolas Gallagher's post on this same kind of technique.
It's a bit complicated to read, but fairly simple to execute.
I've known for awhile now that other folks have been using newer media query features in SCSS to place their styles directly inline — in the place where that element is being styled. I like this idea because it keeps styles grouped logically. However, it means that older IE (or any user agent that doesn't support media features) will be served only the styles outside of media queries. This is not a huge deal if you're writing your CSS "desktop-first." However, we start with the smallest styles and build up at Sparkbox, so old IE would generally get a linear, single column layout.
Now, some people are ok with this, but I felt there might be another way. After a bit of digging and some fun conversations with my guys (Rob Harr, Rob Tarr, Adam Simpson and Ethan Muller, in particular), we have an interesting solution.
It's called My-Media. It consists of two different versions of two SCSS mixins. The two mixins are:
- my-media: a replacement for @media in your SCSS
- my-base: which all other styles use
These two mixins are defined differently in two separate files. One for user agents that support media queries:
|1 2 3 4 5 6 7 8 9 10 11 12 13|| |
And one for user agents that don't support media queries:
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18|| |
These are used in your SCSS like so:
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35|| |
Then, the aggregate files build our two CSS files uniquely by redefining these mixins like so:
|1 2 3 4 5 6 7 8 9 10|| |
By redefining the mixins for each user agent, we're able to control what is put into the generated CSS. This gives us the ability to serve a large resolution layout to old IE, build with mobile-first CSS, and put our media queries right inline where it makes the most sense.
The one drawback is that it does require you to put all styles in either my-base or my-media. I think this could be worth it, so we'll be experimenting with this more in the coming weeks!
Thanks again to my team for all the insight and feedback. Great ideas are never built single-handedly...
Ideas on how to make this better? Chime in, please!