“Mobile first” CSS and getting Sass to help with legacy IE
Taking a “mobile first” approach to web development poses some challenges if you need to provide a “desktop” experience for legacy versions of IE. Using a CSS pre-processor like Sass can help.
One aspect of a “mobile first” approach to development is that your styles are usually gradually built up from a simple base. Each new “layer” of CSS adds presentational adjustments and complexity, via CSS3 Media Queries, to react to and make use of additional viewport space. However, IE 6/7/8 do not support CSS3 Media Queries. If you want to serve IE 6/7/8 something more than just the base CSS, then you need a solution that exposes the “enhancing” CSS to those browsers.
Popular existing options
An existing option is the use of a CSS3 Media Query polyfill, such as Respond.js. However, there are some drawbacks to this approach (see the project README), such as the introduction of a JavaScript dependency and the XHRing of your style sheets, which may introduce performance or cross-domain security issues. Furthermore, adding support for CSS3 Media Queries is probably not necessary for these legacy browsers. The main concern is exposing the “enhancing” CSS.
Another method, which Jeremy Keith has described in his post on Windows mobile media queries, is to use separate CSS files: one basic global file, and an “enhancing” file that is referenced twice in the <head> of the document. The “enhancing” file is referenced once using a media attribute containing a CSS3 Media Query value. This prevents it being downloaded by browsers (such as IE 6/7/8) which do not support CSS3 Media Queries. The same file is then referenced again, this time wrapped in an IE conditional comment (without the use of a CSS3 Media Query value) to hide it from modern browsers. However, this approach becomes somewhat cumbersome, and introduces multiple HTTP requests, if you have multiple breakpoints in your responsive design.
Getting Sass to help
Sass provides some features that help make this second approach more flexible. The general advantages of the Sass-based approach I’ve used are:
- You have full control over how your style sheets are broken up and reassembled.
- It removes the performance concerns of having to reference several separate style sheets for each breakpoint in the responsive design, simply to cater for IE 6/7/8.
- You can easily repeat large chunks of CSS in separate compiled files without introducing maintenance problems.
The basic idea is to produce two versions of your compiled CSS from the same core code. One version of your CSS includes CSS3 @media queries and is downloaded by modern browsers. The other version is only downloaded by IE 6/7/8 in a desktop environment and contains no CSS3 @media queries.
To do this, you take advantage of the fact that Sass can import and compile separate .scss/.sass files into a single CSS file. This allows you to keep the CSS rules used at any breakpoint completely separate from the @media query that you might want it to be a part of.
This is not a CSS3 Media Query polyfill, so one assumption is that IE 6/7/8 users will predominantly be using mid-size screens and should receive styles appropriate to that environment. Therefore, in the example below, I am making a subjective judgement by including all the breakpoint styles up to a width of 960px but withholding those for any breakpoints beyond that.
The ie.scss file imports numerous other files, each containing a layer of CSS that builds upon the previous each layer of CSS. No CSS3 @media queries are contained within the files or the ie.scss file. It then compiles to a single CSS file that is designed to be served only to IE 6/7/8.
// ie.scss
@import "base";
@import "320-up";
@import "480-up";
@import "780-up";
@import "960-up";
The style.scss file imports the code for each breakpoint involved in the design (including any beyond the limit imposed for legacy versions of IE) but nests them within the relevant CSS3 @media query. The compiled version of this file is served to all browsers apart from IE 6/7/8 and IEMobile.
// style.scss
@import "base";
@media (min-width:320px) {
@import "320-up"; }
@media (min-width:480px) {
@import "480-up"; }
@media (min-width:780px) {
@import "780-up"; }
@media (min-width:960px) {
@import "960-up"; }
@media (min-width:1100px) {
@import "1100-up"; }
The resulting CSS files can then be referenced in the HTML. It is important to hide the ie.css file from any IE-based mobile browsers. This ensures that they do not download the CSS meant for desktop versions of IE.
<!--[if (gt IE 8) | (IEMobile)]><!-->
<link rel="stylesheet" href="/css/style.css">
<!--<![endif]-->
<!--[if (lt IE 9) & (!IEMobile)]>
<link rel="stylesheet" href="/css/ie.css">
<![endif]-->
This Sass-enabled approach works just as well if you need to serve a basic style sheet for mobiles without CSS3 Media Query support, and prevent those devices from downloading the CSS used to adapt the layout to wider viewports. For example, you can avoid importing base.scss into the ie.scss and style.scss files. It can then be referenced separately in the HTML.
<link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/style.css" media="(min-width:320px)">
<!--[if (lt IE 9) & (!IEMobile)]>
<link rel="stylesheet" href="/css/ie.css">
<![endif]-->
You’ll notice that I didn’t wrap the style.css reference in a conditional comment to hide it from legacy versions of IE. It’s not necessary this time because the value of the media attribute is not understood by legacy versions of IE, and the style sheet will not be downloaded.
In different circumstances, different combinations of style sheets and media attribute values will be more appropriate.
Summary
Even if you want to don’t want to use any of the Sass or Scss syntax, the pre-processor itself can help you to write your CSS in a “mobile first” manner (with multiple breakpoints), provide a “desktop” experience for IE 6/7/8, and avoid some of the performance or maintenance concerns that are sometimes present when juggling the two requirements.
I’m relatively new to using Sass, so there may be even better ways to achieve the same result or even to prevent the inclusion of IE-specific CSS unless the file is being compiled into a style sheet that only IE will download.
Comment on this post
Please wrap code fragments in <code> tags, wrap blocks of code in <pre><code>, and use JsFiddle to post working examples.
22 comments
Thierry Koblentz says…
What a refresher!!
Someone who actually thinks that not everybody has chosen to completely *ignore* IE users.
Thanks Nicolas! :)
Jon z says…
Maybe it’s not the right forum for this question but why is it a best practice to start with the smallest viewport and then build up from there, rather than the reverse?
Hans Christian Reinl says…
Really great idea for the mobile first approach!
One think which I (and many others) don’t like about polyfills for example is, that you provide more code for old browser which are relatively slow. This could cause real performance issues.
As you pointed out this is no polyfill. Respond.js for instance needs to get rendered by the browser, request CSS-files via XHR, parse these and apply new styles. This is a great hit for performance.
What I really like about this idea is that oldIE does not have to handle more code than other browsers. The organisation of the CSS-code is really clean, DRY principle, and organized.
Thank you for sharing your thoughts.
Peter Wilson says…
I’ve created a gist showing how to do this in LESS, it’s not as easy as Sass but may be acceptable for users (such as myself) who prefer LESS.
https://gist.github.com/1407227
In the past, I’ve used the Keith method with two http requests for IE desktops but will consider revising down the track now I’m using a pre-compiler.
Phil Green says…
@Hans: It’s even better than that. Because there are no media queries in the files, the IE-centric stylesheet will basically comprise a bunch of CSS with the potential for multiple identical references exists (h1 for 320px is overridden for 480px, which is overriden for 960px, for example). Sass will compile all those into one making for a leaner stylesheet for the less capable browser and a fatter one for the big boys.
Rafael Trabasso says…
I noticed that most people around the web just tend to ignore IE, say it doesn’t matter etc. From behind your Macbook that is easy to say.
But in developing countries like Brazil people still use lots of old computers and have little knowledge of computer-related things – that includes downloading a new browser, for example. And guess what Operating System is running on most of those old computers?
So for a person like me that works with websites in Brazil, IE is hardly a thing to ignore.
Thanks for this article, I’m having a painful time trying to make modern websites with HTML5, CSS3 and all the new buzz while having to serve some decent content for the IE 6-7-8 users that are still around 50% of the users on the average site here.
Gustaff Weldon says…
Nicolas, thanks for an interesting post. One thing that I’m wondering about is the first example when you use 2 conditional comments:
What will be downloaded by IEMobile in this case? If I understood correctly, the first conditional, although ignored by non-IE browsers, will hide
style.cssfrom all IE < 9 (mobile and desktop). This excludes IEMobile on Windows Phone (not sure about the latest Mango update version).The second conditional, also excludes IEMobile explicitly. So, what’s left for IEMobile which is based on IE7/8? Can you explain this part a bit?
Nicolas says…
@Gustaff: You’re right! In the first example, IEMobile 7 won’t download any CSS…to be honest, this was an oversight on my part. I will update the example so that IEMobile 7 downloads
style.css, in the same way as the version of IE packaged with the Mango update will. Thanks!Hans Christian Reinl says…
@Phil Didn’t know that SASS will combine these styles together. But this is even better! Love it!
Nicolas says…
@Hans @Phil I’m not sure that is actually correct.
Webstandard-Blog (Heiko) says…
Very interesting Nicolas! I think Sass is goning to be more and more a good opinion for CSS. Thx for sharing!
Phil Green says…
@Nicolas: Oh bunnies, you’re right. Sorry, attributed reduction behaviour in an all-in-one solution to SASS
Aki Karkkainen says…
This article is a gem, absolutely brilliant thinking.
After reading it, I went back to the drawing board and created the same thing in Ant:
https://github.com/akikoo/one-web-boilerplate
(It’s a one web boilerplate that I’ve put together from various resources. So now it includes this method too.)
Sass and LESS are good but I haven’t yet used them in any real-world projects. Instead, I’ve been using Ant for years for building and deployment which is why I wanted to see how your idea could be migrated into it. Pre-compiling tools are really cool.
Thanks again Nicolas for a great post!
Aki Karkkainen says…
Forgot to add in my previous comment: remember to check the credits section in “one web boilerplate” ;)
HTML5 Boilerplate is so full of goodies that I don’t even remember how we survived before that.
Ward says…
@Thierry @Rafael Wow, considering the hundreds of hours I have spent debugging for IE this type of comment actually kind of pisses me off. I am wondering who these people are of which you speak. I, for one, do not see this type of attitude on the web except occasionally in some stream of comments. I would wonder where you are spending your time on the web.
Ryan says…
This is brilliant! Thanks for publishing the solution :)
I’m new to SASS so this may not be quite right but could you also set a variable in the style.scss file such as:
$ie = 0;And then add
$ie = 1toie.scssto exclude certain CSS from within your imported.scssfiles from IE, for example:jhawes says…
I can still say I frequently check the ie6countdown.com site with anxiousness – hard to believe China is still near 30% !!
As @Thierry said, IE support is still a must these days – its just not going to disappear so we gotta support it as annoying as it is sometimes.
Great blog.
Robin says…
@Ryan: Good idea. That could save us some file size.
Rick Harris says…
Thanks, @Nicolas! Your ideas here motivated me to dig a little deeper for a
solution that fits my needs in how I organize my CSS. So, thought I would share.
Sass 3.2 (pre-release) actually adds support for passing style blocks to
mixins, which means you can pretty easily create a mixin to make media queries
much easier to write. I’ve been using a customized version of Chris
Eppstein’s example in a lot of my partials (I like to keep all the code,
including media-dependent styles, for a particular module or layout in its
own file). This precluded me from being able to use this method, since I have
media queries spread around a lot of my stylesheets.
But, this new Sass feature allows you to create an IE-specific stylesheet that overrides the behavior of the media query mixin so that it just includes all the styles without the actual media queries. This means that the only modified part about the IE stylesheet is the media query mixin – all other stylesheets can go in unmodified (media queries and all). See the gist I created for how to set this up.
Hans van Wijk says…
Have been experimenting myself with this (using less). Think it is a great solution and very easy to implement.
Eric says…
I’m so elated to have read this post and look forward to using this technique on my next responsive design. IE and Responsd.JS have been more difficult that I’d liked for responsive mobile-first design. This is brilliant, thank you!
Jake Rocheleau says…
Wonderful writing man appreciate your ideas.