How Should We Write Media Queries?
For some time now a doubt has been growing in me about the way we write media queries. Since this whole responsive web design thing started, most folks have been doing something like this:
Now, this certainly works, but is it what we really want? Do we really want these styles only to apply to the screen media type? From the spec, here's a list of recognized media types:
Now, I think it's natural to assume that screen means anything with a screen. Unfortunately, that's not the case. According to the spec, "Media types are mutually exclusive in the sense that a user agent can only support one media type when rendering a document."
Wait a second — if user agents can only support one media type and we write "screen and (min-width: 30em)" that means our sites in projection mode and on TVs will not get these styles.
Well, not quite.
To some extent, rampant use of "screen and ..." media queries has already broken the media type attribute. As Jason Grigsby said in his Breaking Development talk, "The Immobile Web" (check out minute 36), every TV he tested responded "true" to the screen media type and "false" to the tv media type. Unfortunately, we web developers have forced this to be the case by writing our media queries as above. Had the teams building smart TVs opted to support the tv media type, they wouldn't have gotten any styles on the sites built to only support screen.
OK. So, what to do?
At Sparkbox, we've been writing our queries without media types, like this:
We hadn't had any issues with this approach. Then, not long ago, Matt Griffin (that super smart, ultra handsome, bearded wonder from Bearded) wrote a nice little piece containing some examples of media queries. In his examples, he uses "only screen and (min-width: 500px)" which reminded me that a lot of really smart people are still serving styles exclusively to the screen media type.
I thought I should get a second opinion, so I started discussing this with Matt.
After a few minutes on Skype, he and I both agreed that more thought was warranted. We concluded that leaving the type attribute out completely worked (and Scott Jehl concurred), but now we're applying these styles to all user agents, regardless of type. That means, print, braille, embossed, etc., as well as screen, projection, and tv. So, we started considering our options. What we really wanted was something like this:
...which is a completely invalid query. The limitations described in the spec were not encouraging. Nevertheless, Rob Harr and I created a slew of tests to see if we could bend it to our will. It wasn't meant to be. That "not" keyword is really only intended to negate the entire query, as opposed to only the type attribute. We documented our failure on the Bearded blog, and started asking around to see if anyone else had ideas for us.
I ended up having a discussion with Stephen Hay on Twitter which got me pointed in a new direction. He mentioned that we may be able to nest media queries by specifying a media attribute on a link element in the head of our HTML, and then applying media query blocks in the CSS file itself. That made immediate sense, so I quickly created a rough example in the "/nesting" directory of a Github repo. The example I created is actually a combination of Stephen's suggestion and Jordon Moore's ideas about how print stylesheets could fit into a responsive style structure. I requested a bit of feedback and didn't hear any objections. In fact, Stephen jumped on the job and did his own write-up explaining one of the more potent possibilities with the technique, nesting media queries.
So, here's what we're doing in the example. In the head of our HTML document, we're linking to two separate CSS files like so:
In basic.css, we define our simplest layout and include a print block at the bottom to make adjustments for printing, as Jordon suggested in his article:
Then, in mq.css we define the rest of our styles for various breakpoints — but hidden behind the "not print" media attribute. Our (theoretical) more complex layouts are only being served when "not print" is true:
This actually works quite well, as far as I can tell. I figured the next step was to get it implemented where it can be tested a bit better, so I made some slight tweaks to my one-pager at http://bencallahan.com and found a few additional issues.
Here are the link elements from the head of my site:
You can see that I added a few additional media types to exclude for the "mq.css" file. You'll also note that I left those media types out of the reference to "nomq.css" (for older IE) as these browsers don't support media queries. I found that leaving the "not" media attribute on for non-media query supporting browsers caused them to ignore the linked CSS file.
Instead, I've just scoped the "nomq.css" file to the screen media type.
Another issue here is that I've added an additional request to the server to make this work. I really don't like that idea, but I haven't figured out how to avoid it yet.
After reviewing all of this with Matt, he and I still feel like there's more to consider.
Is all of this worth the trouble?
Leaving the media type off would serve more complex layouts to all media types. Then we'd have to unstyle these complexities in a print stylesheet. Also, we don't really know what is happening for other media types such as braille, embossed, etc. (Anyone have the ability to test this for us?)
Another alternative would be to whitelist the media types to which we'd like to serve a more complex layout. Something like:
This just doesn't seem as future friendly as I'd like. We don't know what new, capable media types are around the corner. I'd hate to think that we've completely killed the usefulness of the media type in the future.
It may not feel like this is a painful problem now, but we must start using media types in a future friendly way. If we don't, they completely lose their usefulness.
What's the takeaway?
At Sparkbox, we're seriously considering writing our media queries using the technique I've implemented on http://bencallahan.com. It may be too late to rescue the tv media type, but I still think scoping all of these styles to screen only is the wrong answer.
I also think there are quite a few other use cases for the techniques explored here. Nesting media queries like this is something I'll continue experimenting with. In general, this kind of thinking makes me want to better understand the stuff we take for granted in our everyday work.
And finally, I hope this encourages you to consider how you build things for the web. I've found great inspiration in working with all of the people mentioned in this article. Collaboration is the cross-pollination of the web, but it requires you to be intentional.
I'd like to thank all of those mentioned above for their collaboration in this process. In particular, Matt Griffin and Rob Harr were gracious with their time.