Or “A perfect blend of best practices and developer comfort, using LESS CSS”
Mediaqueries are the new black. They really are, I checked. Ever since A List Apart’s article on Responsive Web Design it seems like every man and his dog are jumping on the CSS3 mediaqueries bandwagon. But as with all bandwagon jumping, enthusiasm can quickly get in the way of efficiency and common sense.
Mediaqueries are awesome, but come with a lot of gotcha’s.
Using mediaqueries doesn’t guarantee your site is optimized for mobile.
Optimization is more than just changing the layout. Mobile users have a high probability of having a slower than broadband connection, and so it isn’t a good idea to have them download images made to be viewed at resolutions far higher than their current device.
… but if you look at most sites displaying responsive layouts today, that’s exactly what they’re doing. The first layout they finalize is the standard desktop version, optimized for 1024×768, and they then use mediaqueries to twist and distort their desktop version into a mobile frame. Not only does this result in a coding nightmare where you’re constantly having to reset your own CSS rules, but it also misses the point of having a mobile site by having their users first download all the desktop-resolution art assets, and then download the smaller images on top of that.
So the best practice for making mobile sites is to build for the smallest screen size first, and then using mediaqueries to create ever bigger layouts as the screen-size goes up (Andy Clarke’s 320andUp boilerplate modification emphasizes and encourages this practice). Working like this means that the mobile browser won’t download any of the bigger images that you define in the higher-res mediaqueries. So the mobile version of a site won’t download the 1600×1200 background image you use in the desktop version, for example.
However, this technique, while being the best practice, is impractical for those of us living in the real world where not everyone (who’s not on a mobile device) uses Google Chrome on a Macbook Air in a trendy coffeeshop. I’m talking of course about the dreaded Internet Explorer.
Mediaqueries break in older browsers.
And by “older browsers” I mean of course IE6, IE7 and IE8. No other browser-manufacturer has upgrade schemes that are as broken as IE’s which means that we have to continue to support browsers that are literally *years* out of date. (Note: when’s the last time someone asked you to fix a browser issue with Firefox 2? Exactly my point.)
So anyway, IE right up until version 8 has absolutely no support whatsoever for mediaqueries. The above mentioned 320andUp uses the excellent respond.js script to force IE to recognize and respond to mediaqueries as a workaround to this issue, but I have several reservations against using this.
The first is that it doesn’t really improve IE users’ experience with the site. Instead of getting a responsive website, they’re constantly treated to a page that first looks broken, than flashes a bit and then looks okay. Not exactly the shining example of responsive webdesign we’re looking to serve these people.
And then the final reason for using respond.js being a bad idea is that, as a front-end developer on a strict deadline, having not just one, but 2, 3 or even 4 different layouts to debug in Internet Explorer isn’t exactly a fun thing to look forward to.
And it’d be mostly wasted effort as well, since most people using IE won’t expect (or need) to view your site in many different resolutions.
So why give yourself the extra stress? Click on to read my solution.
LESS is more
I’ve been using LESS CSS (lesscss.org) religiously for over a year now and I just keep finding new and better uses for it. For the uninitiated, LESS is a language built on top of CSS and adds a whole suite of extra features, such as nesting selectors, mixins, color operators and variables.
I’ll first show you the structure I’m using:
This structure works as follows: both style.less and IE.less import all the other .less files in the mediaqueries/ and libs/ directories, like so:
As you can see, inside the mediaqueries/ folder I have a single .less file for every layout I’m going to build and support. Global.less is the basest layout, which is essentially what we’ll be serving to mobile browsers as a baseline. All my mediaqueries are built up on top of eachother, so that a user browsing the site with a minimum desktop resolution of 1024×768 will get the rules of all mediaqueries right up until desktop.less, ignoring huge.less until the user resizes the browser window to be bigger than 1280 pixels. I do this by building my queries around solely a min-width requirement, like so:
Inside each of the size-specific .less files, I write all my styles wrapped inside a mix-in, with a pre-filled parameter, like so:
That funky shit you’re seeing are LESS’ support for parametrized classes. It’s more commonly used to create reusable mixins, to have variably sized rounded corners, for example, but I’m using it here to prevent LESS from just inserting the generated code in the parent file where the import statement is declared. So even though I’m importing the file at the top of style.less, the compiled output won’t include whatever code I’ve put inside that parametrized class. This is important for later on. Now, this is the final version of style.less:
When you compile this file, it will automatically expand the layout specific mixins inside the correct mediaquery blocks. In a perfect world where everyone uses a decent, modern browser we could call it a day at this point, but now we’ll make it so that Internet Explorer can only see one layout, namely the desktop resolution one.
In ie.less we put the following:
As I’ve mentioned before, all layouts inherit from each other, so that the desktop resolution layout re-uses rules defined in both the tablet, mobile and global layouts. Expanding all media-queries after one another means that IE will be served a cascaded layout that only works for the basic desktop resolution. Using conditional comments, we can now link both compiled stylesheets in the HTML, like so:
This way, all versions of IE from version 8 downwards will ignore the mediaquery laden style.css and load ie.css while all good browsers ignore ie.css and just use style.css.
I hope others can learn from this technique so that we can all move forward towards a truly responsive and beautiful web, untethered by the restraints imposed by older browsers.