Progressive Enhancement with CSS Media Queries
Tuesday, July 20, 2010
There have been a number of articles recently talking about how to use media queries of late by Hicks, Colly and others; it has even had some air time on Dan Benjamin's 5by5 network. I remember playing with the idea of it during a stint of research on Apple's website so, when I spotted what Jon Hicks managed to get out of it, I had to give it a try.
NB. This is hopefully going to be an article that gets a number of redrafts over the next few weeks until it's perfect. I'm using my freelance site as the testing ground for it so dig in to my site to see. I would like some help from device owners who can test some of these layouts on their iPads/Androids/etc. Tweet me if you want to offer any help.
First Attempt
As part of trying to be a tidier coder I wanted to look at splitting this all out in to multiple CSS files so as to keep it easier to update and manage. My first draft process went like this:
- Create screen.css
- Add the CSS for the high resolution version of the site
- Create 1024.css
- Add loads of hacks to (to 1024.css) give netbook users an easier time
- Create 640.css
- Add loads of hacks (to 640.css) to give iPad users an easier time
- Create 320.css
- Add loads of hacks (to 320.css) to give iPod users an easier time
At the end of it I had 4 gigantic CSS files with various declarations of varying complexity, !important at the end of a lot of lines, many resets for paddings and I was really unhappy with it. Ultimately, to give visitors a helping hand with their smaller devices (or legacy browsers) you'd need to add large portions of CSS just to hack it down to render well. I decided a progressive enhancement made more sense than graceful degradation.
Second Draft
Before taking it any further we need to make sure we have <meta name="viewport" content="width=device-width"> in the <head> or else live testing is going to produce strange results on an iPhone/iPod Touch.
Next you need to decide upon a range of display widths for your layout. It will very much depend entirely upon the particular design, as to whether you need to offer more than 2 or 3 varieties. I wanted to use 4 columns at a higher resolution and allow it to reduce sensibly for netbooks, iPads, and mobiles respectively.
At this stage I've only been able to research Apple devices so anyone able to offer me some help with perfecting this with Android and other mobile browsers (@ppk wink wink) will really be of great help.
To get this to work correctly, you need to have the base stylesheet with the bare minimum needed for a plain layout and then have additional stylesheets to enhance the layout as display width increases:
Layout & CSS
<body id="home"><div id="main">
<header id="header"><h1>Foo</h1></header>
<nav id="menu">
<ul><li><a href="#">Lorem</a><li><a href="#">Lorem</a><li><a href="#">Lorem</a><li><a href="#">Lorem</a></ul>
</nav>
<section id="showcase">
<article><h2>Lorem</h2><p>Lorem ipsum</article>
<article><h2>Lorem</h2><p>Lorem ipsum</article>
<article><h2>Lorem</h2><p>Lorem ipsum</article>
</section>
<div id="content">
<div class="c_primary"></div>
<div class="c_ancillary"></div>
</div>
<div id="sidebar">
<div class="s_primary"></div>
<div class="s_ancillary"></div>
</div>
</div></body>
</html>
- <link rel="stylesheet" type="text/css" href="http://web1984.com/css/jun2010/default.css" media="all">
-
This is your default stylesheet. A simple one column layout with some standard colours. Centre aligned header and navigation but other than that it's pretty plain. I've used media="all" but it's unnecessary.
- <link rel="stylesheet" type="text/css" href="http://web1984.com/css/jun2010/640.css" media="screen and (min-width: 480px),(min-width:320px) and (orientation:landscape)">
-
I regret naming this 640.css as that is the upper bound before the next stylesheet activates but I'll continue like this for now and fix it soon.
This one activates at 480 pixels in width. I chose 480 pixels as it's the width of the iPhone in landscape mode. There are two media query statements here because the iPhone device width doesn't alter when the orientation is altered but it does recognise orientation.
#sidebar { display: table-cell; width: 240px !important; } #content { display: table-cell; border-collapse: collapse; border-spacing: 0px; }This turns the 2 divs (with display:block) into a 2 column layout with the right hand sidebar only taking up 240px
- <link rel="stylesheet" type="text/css" href="http://web1984.com/css/jun2010/1024.css" media="screen and (min-width: 641px) ">
-
Now we cater for netbook/iPad owners. At this stage we aren't catering to the smaller mobile devices so we can get away with one media statement. This will apply further enhancements to the CSS until the display width exceeds 1024 pixels.
#menu ul { text-align: left; } header#header h1 { text-align: left; } #showcase { display: table; border-collapse: separate; border-spacing: 24px; padding: 0; } #showcase > article { display: table-cell; width: 33%; position: relative; text-align: left; } #showcase > article h2 { display: block; } #showcase p { display: block; } #showcase > article h2 a { padding: 0; }This time we've kept the main content layout at 2 columns but created a 3 column layout for the web app showcase at the top of the site. As the layout is wide enough I've unhidden the paragraphs that were hidden (display:none) at the lower resolutions. T'would be contestable as a waste of bandwidth but I find it makes sense to reduce the page clutter. Visitors on smaller devices could have clicked/pushed their way through to the pages that they link to.
- <link rel="stylesheet" type="text/css" href="http://web1984.com/css/jun2010/1440.css" media="screen and (min-width: 1025px)">
-
This is the last stage. Big screen layout. I add all the declarations to create a 4 column layout
#main { position: relative; } #menu ul { position: absolute; font-size: 200%; right: 12px; top: 0; } #menu a { padding: 2em 12px 0.5em; } #menu a:hover { padding-top: 1.75em; border-top: 0.25em solid #1f8199; } #sidebar { width: 480px !important; } #sidebar div.s_primary, #sidebar div.s_ancillary { display: table-cell; width: 50%; padding: 0 12px 0 0; margin: 0; } #content div.c_primary, #content div.c_ancillary { display: table-cell; width: 50%; padding: 0 12px 0 0; margin: 0; }Here I've made the 4 divs (c_primary, c_ancillary, s_primary, s_ancillary) into table cells and thereby created the final 4 column layout. The fact that this will only truly work within the more advanced-CSS3 capable browsers means that I don't need to worry about hacks. In fact IE6-IE8 are still only displaying the default.css; you can remedy the IE6-IE8 situation quite easily with some conditional comments at the final stages of your project.
Further Reading
- A pixel is not a pixel is not a pixel—@ppk of Quirksmode
- A tale of two viewports—@ppk of Quirksmode
Comments