Learn what you need to know to set up media queries that maximize efficiency and robustness for your particular project. There are pros and cons to making your media queries embedded versus external, overlapping versus stacking your media queries, starting with mobile versus desktop styles, and using conditional comments versus JavaScript to add support for IE 8 and earlier versions.
CSS3 media queries are dead simple, in terms of their syntax. You’ve got an @media
directive, a media type (which you already know from good ol’ CSS 2, like screen
, print
, all
, etc.) and one or more media features (the characteristics we’re testing against). That’s it:
@media screen and (max-width:500px) {
}
There are some additional little syntax details, but this is basically all you need to know to actually make a media query work. Once you memorize this short, simple syntax and the various media features that are available, you could technically say that you know how to use media queries. But knowing how to use media queries effectively requires a whole lot more considerations than just where to put an @ or {.
Designing web layouts with media queries is a process. You need to keep them in mind from the very beginning and make decisions at several points about how to integrate them in ways that will make the most sense for your site. There are very few always-right or always-wrong answers. What type of media query set-up would work best will depend on your site, your users, and your own capabilities and experience. But I wanted to cover the pros and cons of some of the essential considerations that go into crafting robust media query-driven layouts. These considerations include whether to:
This article is just as much for me as it is for you—it can be hard to keep track of all the different configuration variations you can use! Hopefully I’ll be able to make the pros and cons of the various approaches clearer so you can use this article to guide your decisions when you start a project involving media queries.
How to include your media queries: embedded vs. externalThere are two ways to include media queries in your site: embed them within a style sheet or include them in a call to a separate, external sheet.
Here’s what an embedded media query looks like (pretend that we’re inside a style sheet):
body {
background: gray;
}
@media all and (max-width:500px) {
body {
background: blue;
}
}
For an external media query, simply extend the existing media part of the link
element or @import
rule:
<link href="narrow.css" rel="stylesheet" media="only screen and (max-width:500px)">
@import url(narrow.css) only screen and (max-width:500px);
Browsers that don’t support media queries won’t download these sheets, but browsers that do will download them all, regardless of whether they’re needed or not for the current viewing scenario. (The background images inside the currently-not-needed sheets won’t download, however.) On the one hand, this makes sense—the user could change his or her orientation or window size, and those alternate styles would suddenly need to be called into action. On the other hand, Greg Rewis found that even if you create a sheet that it seems like a device could never possibly use, such as a sheet for a max-width
of 700 pixels never being needed by an iPad with its 768 x 1024 resolution, the device will download it anyway. But Chris Coyier pointed out to me that you could have an iframe
in a page, for instance, that might need to use that smaller style sheet—so on the third hand, I guess this behavior is logical and unavoidable, if not perfect.
* I’ll go into the details of both of these approaches to dealing with old versions of IE later on in this article, so sit tight if this IE stuff doesn’t make sense just yet.
The bottom lineIn most situations, I think that embedded is the better way to go. I’ve never been a fan of separating out styles into separate sheets because I find it harder to keep things organized and easier to forget those extra sheets when debugging or updating. Plus, it adds extra HTTP requests, which are more expensive in terms of performance than having a single sheet that’s larger in file size. Because media-query-supporting browsers will download those extra sheets even they don’t currently need them, the smaller file size that you gain by separating the media queries into their own sheets is really only a benefit to browsers that don’t support media queries, as they won’t download those extra media query sheets.
But again—and this is the last time I’m saying this, but it applies to everything in this article—the best approach depends on your project.
How to use the cascade: overlapping vs. stackedRegardless of whether you make your media queries embedded or external, you also need to decide whether you want them to overlap, bringing the cascade and specificity into play, or whether you want to “stack” them so only one media query applies at once.
Here’s what overlapping media queries look like (this example is embedded, but the same could be done with external sheets):
body {
background: gray;
font-family: sans-serif;
}
@media all and (min-width:500px) {
body {
background: blue;
font-family: serif;
}
}
@media all and (min-width:700px) {
body {
background: red;
color: white;
}
}
Do you see how these media queries are not mutually exclusive? Both apply to windows greater than 700 pixels wide. If my viewport was 800 pixels wide, for instance, it would meet both the minimum width of 500 pixels and the minimum width of 700 pixels and apply the styles from both media queries. I’d have a red background with white text in a serif font.
When you overlap your media queries, the cascade and specificity come into play when determining which rules to use. For instance, if I used the same exact media queries containing the same exact CSS, but changed their order so that the min-width:700px
one was first, I’d get different results:
body {
background: gray;
font-family: sans-serif;
}
@media all and (min-width:700px) {
body {
background: red;
color: white;
}
}
@media all and (min-width:500px) {
body {
background: blue;
font-family: serif;
}
}
Now my 800-pixel-wide viewport would have a blue background instead of red—the rule that comes later with the same specificity wins.
Instead of overlapping your media queries, you can stack or isolate them so that each is mutually exclusive:
body {
background: gray;
font-family: sans-serif;
}
@media all and (min-width:500px) and (max-width:699px) {
body {
background: blue;
font-family: serif;
}
}
@media all and (min-width:700px) {
body {
background: red;
color: white;
font-family: serif;
}
}
Now only one of these media queries can apply at a time: the first applies in viewports between 500 and 699 pixels, and the second applies at 700 pixels and up. This means you don’t have to worry about cascade or specificity any more, but you do have to repeat any styles that you want to apply in both situations, such as font-family:serif
in this example. On the other hand, you don’t have to override styles from earlier media queries that you don’t want to apply in the later media queries. So neither setup always leads to more or fewer lines of CSS.
Whether you overlap or stack also has an impact on which assets get downloaded in WebKit browsers. If you have multiple media queries that apply to the same situation (such as the 500px and 700px media queries both applying to the 800px viewport example above), WebKit-based browsers will download all the images in all of them, regardless of whether a later media query overrides one of the images in an earlier one. (This also happens with the styles outside any media queries, by the way.) This doesn’t happen if the media queries are stacked; in this case, WebKit will only download the images called for in the single, currently applicable one. (But again, it will download any images outside the media queries too, even if later overridden.) This handy information is from Greg’s “CSS3 Media Queries? Download Answers” and Cloud Four’s “Media Query Image Download Test.”
The pros and cons Overlapping vs stacked media queriesI think overlapping media queries is more often than not the most efficient way to go. Most sites don’t have radically different looks between media queries—sure, the layout might appear very different, but things like the typography, colors, and various visual effects are usually the same. Because of this, I’ve found that in most cases you’ll end up writing a lot more lines of CSS if you stack your media queries and don’t get to take advantage of the cascade. (Hooray for the cascade!)
However, if you do happen to have a site that has very different styles in each media query, stacking may be more efficient than overlapping. Also, because of WebKit’s downloading behavior, if you’re switching a lot of images between media queries, it may be wise to stack those queries instead of overlapping them, even if that means more lines of CSS and more chance of forgetting to update a rule inside multiple queries.
Which styles to make the “default”: mobile vs. desktopWhile it’s possible to put all of your styles inside media queries, you’ll almost never see this, as browsers that don’t support media queries will get no styles whatsoever. What usually happens is that a chunk of styles sit outside media queries, either inside your single style sheet or in their own style sheet using a standard @import
call or link
, and these essentially become your “default” or starting styles. You then layer on one or more media queries to form alternate styles for different scenarios.
Media queries aren’t just for creating different layouts for different screen sizes, but let’s face it, that’s their primary use right now—and a dang good one. So that’s what I’m focusing on here: whether to make the small-screen styles the default or whether to make wider-screen styles the default. A few caveats, however:
OK, are we all good? Good. Moving on.
Once again, WebKit’s downloading behavior is a big factor here. If you make the desktop styles the default and then override some of its assets in a mobile media query, either by setting new background images or setting elements that contain background or foreground images to display:none
, Safari on iOS will still download the overridden or hidden desktop assets. The reverse is true: when mobile styles are the default, desktop Safari and Chrome will download all the mobile assets, even if overridden or hidden by the desktop styles.
Update May 23, 2012: It’s appears it’s not just WebKit that does this. Tim Kadlec found that nearly all browsers do this when you use display:none
on the element as the way of overriding an earlier background image on that element. If you instead override a background image outside a media query with a different background image inside a media query, Tim found that a few versions of WebKit download both images (as well as Fennec 10+) but that other versions do not. This doesn’t apply if the media query uses min-device-pixel-ratio
as the media feature it’s testing against, however. See tests 2, 4, and 7 on his “Media Query & Asset Downloading Results” article.
This behavior isn’t “wrong,” by the way. It’s common for browsers to download assets that are set to display:none
, as it allows the content to be preloaded and ready-to-go if later revealed by a script, such as a hover effect over text that reveals a thumbnail image. WebKit doesn’t discriminate between situations where the currently hidden image might be needed later, such as if the user can and does resizes her viewport, or if it will never, ever be called into play.
If the downloading of the unneeded image is problematic in your case, there are a few ways to work around it:
div
, and then instead of hiding the div
you hide the div
‘s parent element, WebKit won’t download the image. (Update May 23, 2012: Tim’s test 3 confirmed this, and not just for WebKit: all browsers except for Fennec did not download the image.)These solutions won’t work with all sites, but they are options in some cases.
The pros and cons Mobile-default vs desktop-default media queriesIn most cases, I would advocate making the mobile styles the default, as it allows old mobile browsers to see the correct mobile styles. Yes, desktop IE 8 and earlier will also see those mobile styles, but this is an easy to fix with some JavaScript—a much more quick and straightforward process than getting your mobile styles to apply to non-media-query-supporting mobile browsers when you make desktop the default. Also, the fact that mobile devices won’t have to download any of the assets you call in the media-query-desktop styles is a big plus, as mobile devices are more likely (but definitely not guaranteed) to have slower connections and more limited bandwidth than desktop devices. I’ve made mobile styles the default in the last two sites I worked on, and I anticipate this being my go-to method going forward.
While mobile-first design, as it’s been dubbed by Luke Wroblewski, has become quite popular, and I too will sing its praises, I don’t agree with those who say it’s the only viable way to craft media queries. Desktop-default has a fair share of merit too, as you can see in its pros list above. It’s a great way to retrofit an existing site, since you can add on a chunk of mobile styles instead of having to rewrite all the CSS from scratch. It’s also a great way to get your feet wet with media queries. Designing mobile-first is a big shift in both your mindset and design process, so sticking to desktop-first might be best on your first foray into creating a site utilizing media queries. In Chapter 6 of my book Stunning CSS3, I take a desktop-default approach, as I think this is an easier way to first learn media queries. The default styles are targeted towards a size that most desktop users will see, with styles for both wider and narrower versions layered on. This means that even if I didn’t use JavaScript to fix IE 8 and earlier, or if the JavaScript doesn’t load, users will still see a layout that will work well for the majority of desktop viewport sizes—just the same as they would before we had media queries as an option. Media queries are used as progressive enhancement, not a requirement.
How to deal with IE 8 and earlier versions: conditional comments vs. JavaScriptSpeaking of IE, you probably know that Internet Explorer 8 and earlier versions don’t support media queries. Since these browsers are likely a big chunk of your audience, I suspect you’ll want to figure out a way to get your media queries to work in IE 8 and earlier. You have a couple options: use conditional comments to feed separate media query sheets to different versions of IE or use a pre-fab script to make media queries magically work in IE.
To use conditional comments, you’ll vary your approach based on which set of styles, mobile or desktop, are your default. In either case, you’ll need to have your media queries separated into external sheets, not embedded in a single sheet along with your default styles.
If desktop styles are the default and you want to use conditional comments, you don’t need to really worry about desktop versions of IE 8 and earlier—they’ll get the desktop styles automatically. Sure, they won’t get any variations on those desktop styles that you might have included to better fit every particular viewport size, but if you’re using media queries as progressive enhancement, this isn’t likely to be a problem. Sure, it’s not ideal if an IE user with an 1100-pixel viewport sees the default 700-960-pixel styles instead of the 960-and-up media query, but it shouldn’t be a deal-breaker—the layout they see isn’t likely to look broken or be unusable. They shouldn’t know anything is “wrong.” So there’s nothing extra that has to be done for desktop IE 8 and earlier in this desktop-default scenario.
But the default desktop styles have a much bigger impact in the mobile version of IE used on Windows Phone 7. Luckily you can target it using a conditional comment and feed it your mobile-specific sheet:
<link rel="stylesheet" href="global.css" media="all">
<link rel="stylesheet" href="mobile.css" media="all and (max-width: 700px)">
<!--[if IEMobile 7]>
<link rel="stylesheet" href="mobile.css" media="all">
<![endif]-->
If mobile styles are your default, the situation is basically reversed: mobile-IE is fine without any extra work, but you have to feed desktop-IE the desktop styles using conditional comments. Again, we’re in luck when it comes to conditional comment syntax: it’s possible to craft a conditonal comment that targets IE 8 and earlier—which includes the version of IE on Windows Phone 7—but then also explicitly excludes mobile-IE:
<link rel="stylesheet" href="global.css" media="all">
<link rel="stylesheet" href="desktop.css" media="all and (min-width: 700px)">
<!--[if (lt IE 9)&(!IEMobile 7)]>
<link rel="stylesheet" href="desktop.css" media="all">
<![endif]-->
I learned about this handy conditional comment trick from Jeremy Keith’s article “Windows mobile media queries.” That Jeremy is one clever guy.
Both of these conditional comment variations don’t actually make media queries work in IE—they basically feed an alternate, static layout to IE, not based on viewport size or anything other than IE version number and platform, without any ability to switch dynamically between states. If you need more robust media queries support in IE 8 and earlier, or if you want to be able to embed your media queries in a single sheet, you can instead simply link to a ready-to-use script that detects your media queries and makes them work in non-supporting browsers. There are currently two such scripts:
min-width
and max-width
media features (the only ones I tend to use anyway!). Also, I found it triggered some totally obscure IE bug in a layout I was working on recently. But in general, I don’t have any problems with this script and highly recommend it.Both of these scripts will work in non-IE browsers too, by the way. If you want to limit them to IE so others don’t have to take the HTTP hit, hide the script call in a conditional comment:
<!--[if (lt IE 9)&(!IEMobile 7)]>
<script src="respond.min.js"></script>
<![endif]-->
The pros and cons Conditional comments vs. JavaScript for IE media query support
Plugging in a little script takes no effort whatsoever, so if you’re using embedded media queries, why not use one of the JavaScripts? For the small percentage of people using IE 8 and earlier with JavaScript turned off, I’m not concerned about them simply seeing the default styles; if mobile is default, they’ll get simple but readable and clean, and if desktop is default, it will probably look just right anyway!
Summing it all upBy now you’ve seen that there are lots of important decisions that go into how you set up your media queries for maximum efficiency, robustness, and ease of use. These decisions include whether to:
Hopefully I’ve given you the information you need to make those decisions easier.
There are lots of other decisions you’ll need to make along the way that I haven’t covered, such as:
max-width
or max-device-width
? Use orientation
? That sort of thing.)Don’t let all these decisions scare you off using media queries. Just know that, like any design technique, you can go about it with careful consideration or you can just quickly slap some sloppy media queries on your site. Think through the pros and cons of your media query configuration so that your media queries don’t just work, but work well.
Did you like this?RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4