Respond to Different Devices With CSS3 Media Queries

Emily P. Lewis | January 10, 2011

 

As a hater of horizontal scrollbars, I’ve always been intrigued by layout design that resizes with browser windows. And as a lover of usability and accessibility, I have a keen interest in layouts that resize with text resizing. So when fluid/liquid and elastic design became the trendy web topics in the mid 2000s, I experimented alongside every other bandwagon jumper.

What I discovered was 1) I still suck terribly at math 2) the lazy designer in me much prefers the “known” parameters of fixed design and 3) while both elastic and fluid design were heading in the right direction, they had their limitations:

  • Without setting max-width (which isn’t supported in < IE7) values, line-lengths can become unreadable in fluid layouts.
  • Elastic designs don’t resize unless text is resized.

Using both fluid and elastic together was an acceptable compromise, but the design “flexibility” was limited to size … font size, image size and layout size. Further, the end result of fluid and elastic solutions, particularly for very small or very large resolutions, wasn’t always aesthetically pleasing or as usable as desired. Neither approach provided the finer layout or design control to truly optimize all viewing experiences.

A Device Deluge

Years later, the issue isn’t just responding to text or browser size. It is responding to all of the devices we use today to access the web: iPhone, Android, widescreen displays, Netbooks, tablets, gaming devices … the mobile market alone is enough to make a good-intentioned web designer pass out.

Today, our reality is we no longer have the luxury of working in a fixed-width environment.

Not only do we need to ensure a good user experience on desktop browsers, we have to account for the wider range of monitor displays for desktops and the range of displays for gaming devices and all the mobile devices. Then, of course, not all users expand their browser windows to full size, nor do all handheld users rely on portrait view. Not to mention, new devices hit the market every day. And let’s not forget the increasing number of requests I receive from clients who want an “iPhone site.”

Responsive Design With Media Queries

Last year, Ethan Marcotte introduced the concept of responsive design, whereby you craft a site using technologies that allow the site to adapt and respond to whatever device renders it. Responsive design embraces all devices and displays as part of a single user experience. The goal is to design for the entire user experience, not for disconnected designs aimed at different resolutions.

How does one design for this entire experience? Media queries.

Introduced in the CSS3 specification, media queries give designers the ability to modify how their sites display across resolutions, whether a small BlackBerry, a large 24” desktop monitor, a portrait view or a landscape view.

The goal isn’t to make a site look the same across all viewing experiences, nor is it to target a specific device (like an “iPhone site”). Instead, responsive design uses media queries to detect the client resolution and adjust to fill the display accordingly.

A Quick Look at Syntax

If you know CSS, using media queries isn’t too difficult to grok. Basically, you declare an @media rule that specifies which devices and conditions you want to target:

@media screen and (max-width: 650px){ 
}

Then, nested within the @media rule, declare the style rules for how the site display will change if the query is true:

@media screen and (max-width: 650px){ 
    body {background: #f90;}
}

What this example media query basically says is “If the display device is a screen and the maximum browser width is 650px, then change the page background color to orange.”

Media & Properties

While the above is an extremely simple example, media queries can be quite complex. You can target different media:

  • all
  • handheld
  • projection
  • screen
  • tv

You can also target different properties:

  • Browser window width and height
  • Device screen width and height
  • Device orientation
  • Device resolution
  • Device aspect ratio
  • Scanning process for TV media type
  • Number of bits for color and monochrome

Advanced Testing

Your media queries can test for simple or advanced conditions. For example, test for multiple scenarios by combining conditions with the “and” keyword:

@media screen and (min-width:480px) and (max-width: 960px){ 
}

If any/all of the combined conditions aren’t met, the rule is ignored.

You can also do a test that is similar to an “or” query, by separating conditions with a comma:

@media screen and (max-width: 750px), screen and (max-device-width: 480px), handheld and (max-width:480px) { 
}

You can even do a test that will ignore a condition by using the “not” keyword:

@media not screen and (color){ 
}

Or target a specific condition with the “only” keyword:

@media only screen and (color){ 
}

Embedded, Linked & Import

All of the examples in this article use media queries that are embedded directly in an external CSS file. This is simply the approach I used, not a requirement. You can also apply media queries directly to your CSS links:

<link rel="stylesheet" media="screen and (min-width:480px) and (max-width: 960px)" href="styles.css" />

Or, if you’re writing XML:

<?xml-stylesheet rel="stylesheet" media="screen and (min-width:480px) and (max-width: 960px)" href="styles.css" ?>

You can even apply media queries to @import rules:

@import url("styles.css") screen and (min-width:480px) and (max-width: 960px);

In all of these examples, the styles.css file is only requested if the media query test is true.

Playing Nice With Mobile Devices

As I already mentioned, media queries don’t check for a specific device (like an iPhone or Android handheld), they check for a particular properties of a medium. But not all media are the same.

For example, the iPhone Safari browser has a default layout viewport that can be as large as 1000px, while other mobile browsers may have different defaults. This can throw a wrench into the styles you apply in your media queries. So, to best target the device resolution recommended by each vendor, you should combine your media queries with meta viewport:

<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

The above example utilizes all the available content values to create a 1:1 scale with the device’s viewport width. While this doesn’t guarantee a perfect viewing experience, it does help ensure you are specifying the most optimal width for the device viewport.

Browser Support

Browser support for media queries is quite good among today’s browsers, including mobile. Safari, Chrome, Firefox, Opera, Opera mini, Opera mobile and mobile WebKit all support media queries.

The exception, of course, is IE, which will first have media queries support in IE9. If you can’t wait for IE9, these alternate approaches may help:

Testing

When you work with media queries, you are going to want to test how your display changes with resolution. If you have an iPhone, test on that. If you have an HTC Incredible, test on that. If you have a huge monitor, test on that.  Get it? Always test on the actual device with the actual resolution for best results.

But few of us are so lucky to have a large selection of devices and displays to choose from. Fortunately, you can do some fairly decent testing with what you already have.

For a check of the browser window resolution, just resize your favorite browser. Or, even better, use a plugin that will resize it for you (such as the Web Developer Toolbar). This only lets you test downward in browser size, but it’s a start.

For iPhone simulation, check out iPhoney or use Safari’s built-in user agent switcher. For Android, the SDK provides an emulator.

And then I recommend enlisting your geek friends to help you test on their devices. If your friends are anything like mine, then it is likely that, combined, they have every handheld, monitor and display known to man.

Real World Responsive Design

Now that you know the background, the syntax and the resources you need to get started, let’s take a look at how responsive design can transform a site. For this article, we’ll be looking at the responsive design I’ve applied thus far to my freelance site.

When I launched the site a few months ago, I didn’t utilize any media queries. Since then, it has become an ongoing experiment to make my original design responsive, particularly to make my layout resize with the display and adjust to appropriately fill the display.

The Before

The original design for my site relied on fixed-width parameters optimized for a 1024px screen display, with three floated columns:

.wrap {
padding: 30px 24px;
margin: 0 auto;
width: 960px;
}

section, aside {
float: left;
padding: 25px;
width: 248px;
}

section {
padding: 22px 30px 30px;
width: 568px;
}

This meant I got those dreaded horizontal scrollbars on smaller browser windows:

And on the (few) mobile devices I checked, the site just scaled down to something mostly unreadable without zooming:

An Adaptive Layout

Fortunately, my layout follows a grid that I can use to help me decide how to style it for different resolutions. The default 3-column layout can easily drop to 2 or 1 column for smaller views and expand to 4 columns for larger displays.

These four different layouts can correspond with four different minimum resolutions:

  • Four column: 1200px
  • Default 3 column: 1024px
  • Two column: 800px
  • One column: 640px

These width values are simply the “trigger” viewport widths that will prompt my site layout to adapt. I picked them based mostly on the resolutions I’ve seen otherdesignerstargeting, but you can decide for yourself. Or make it easy and just use Andy Clarke’s hardboiled CSS3 media queries boilerplate or the Less Framework grid system.

For my site, I rolled my own with guidance from those resources. Here’s a snippet of my media query to target screens with resolutions for the two-column layout:

@media screen and (max-width: 800px) {
    .wrap {
        padding: 25px 0;
        width: 750px;
    }
    
    section, aside {
        padding: 15px;
    }
    
    aside {
        margin:44px 10px 0 0;
        width: 240px;
    }

    section {
        width: 423px;
    }

}

And my media query for screens with one-column layout:

@media screen and (max-width: 640px) {
    .wrap {
padding: 60px 0 15px;
width: 600px;
}

    section, aside {
padding: 15px;
}

    section {
width:561px;
}

    aside {
width:250px;    
margin:10px 0 0;
}
}

Each of these queries is added to the bottom of my external CSS files to properly utilize the cascade and override the “default” rules.

And while these examples are just snippets from the live media queries for my site, they do demonstrate how easy it can be to create an adaptive layout. I simply reduced the widths and padding for my core layout elements so the design would best suit the targeted resolutions.

Start Responsive

That said, my layout isn’t (yet) perfect at these lower resolutions. Part of the problem is how I structured my original markup and part of the problem is everything is based on fixed-widths and values. If I had approached the design responsively from the very beginning, I suspect the implementation of alternate layouts would’ve been much easier.

It definitely would’ve been easier for me to implement media queries for an adaptive layout if I had started with a fluid or flexible layout and elastic font sizes. It also would’ve taken less time to modify the designs for different layouts if I’d planned for them from the beginning.

Over time, I’ll address the imperfections in the alternate layouts. But lesson learned: If I’m going to use media queries for future site designs (which I am, because they’re awesome), I need to factor that in during the initial design process … which is really the whole point of responsive design.

Regarding Fonts & Images

The examples above focused solely on the changes to layout. But I also made changes to fonts and images, so that they, too, displayed well across different resolutions.

For example, in the media query that would trigger the two-column layout, I also included styles to better display the text on the home page:

@media screen and (max-width: 800px) {
    #home section[role="main"] h2 {
margin: 45px 0 15px;
line-height: 90%;
}

    #home section[role="main"] h3, #home section[role="main"] > p {
font-size: 17px;
line-height: 100%;
}

#home section[role="main"] p {
line-height: 125%;
}
}

Also, when my site displays on smaller screen resolutions, the images remain at their original size causing issues with the display:

So I took yet another cue from Mr. Marcotte and made my images fluid:

img {
max-width: 100%;
}

This rule just tells images to render at their native dimensions as long as the width isn’t larger than the container.  You can also try a JavaScript solution for responsive images.

While you don’t have to tweak for images and typography along with your layouts, the point is you can. What I recommend is first making your layout responsive and getting comfortable with the media queries themselves. Then tweak typography, imagery and other design as needed.

Optimizing for Mobile

Thus far, I’ve only detailed some of the media queries and style changes I implemented for computer screens. But I also threw a bit of love towards mobile users. Here’s an example media query that targets the portrait resolution most common in today’s smartphones:

@media only screen and (max-width: 320px) {
    .wrap {
width: 90%;
padding: 3% 5%;
}
    
section {
padding: 5%;
width: 90%;
margin: 0;
float: none;
}

    aside {
width: 90%;
padding: 5%;
float: none;
}
    
nav[role="navigation"] li {
float: none;
display: inline;
width: auto;
margin: 0;
}
    header h1 {
float: left;
margin: 0;
line-height: 90%;
}
    header h1 span {
display: block;
margin: 0;
}
}

This query example contains rules that scale the layout down to one column for screens no more than 320px. It also contains some of the rules I’ve assigned to adjust the navigation, logo and internal links to be more appropriate for mobile devices users. And voilá:

Context Is Key

One thing that is particularly important to consider when designing for the mobile experience is context. In addition to designing for smaller screens, mobile design has other constraints:

  • Network speed
  • Mobile browser processing speed
  • Location
  • Touch-based interfaces

And, of course, don’t forget the user. When viewing a site on a mobile device, it is likely (if not guaranteed) that users’ goals are very different than when a site is viewed on a computer screen. Designers need to take all of these factors into account. Some design choices that can help include:

  • Minimize navigation, including those “read more” links that increase hits to the server
  • Minimize :hover styles like drop-down menus
  • Optimize :target areas for small spaces and fat human fingers

But sometimes “mobilizing” your site means serving different content to mobile users.

In a way, media queries can assist with this by hiding (via display: none) content for certain resolutions. I even did it on my own site, removing content that wasn’t really essential for the mobile experience, as well as content that heavily relied on :hover actions:

@media only screen and (max-width: 320px) {
    #project, #contact aside, #footer ul {
display:none;
}
}

But even in this scenario, you are serving the same HTML and content to mobile users. It doesn’t address the reality that if your site’s mobile experience differs dramatically from that on the desktop, you are going to want to serve different content and functionality. Media queries can’t really help you there.

Knowing Is Half the Battle

Media queries are one of those technologies that are extremely simple to implement. The syntax is straightforward, as is the conditional logic. And if you know CSS, the rest is just a matter of plugging away at alternate styles for your queries.

But that’s only half the battle. The real challenge is to embrace responsive design; to design a site with the full user experience in mind, not just the computer browser. And it isn’t just the CSS design, but the visual and structural design (and even planning) of your site that needs to be responsive.

Hopefully in this article, I’ve given you enough to get started and comfortable. When you are ready for more, these resources are great:

 

About the Author

Emily Lewis is a freelance web designer of the standardista variety, which means she gets geeky about things like semantic markup andCSS, usability and accessibility. As part of her ongoing quest to spread the good word about standards, she writes about web design on her blog, A Blog Not Limited, and is the author of Microformats Made Simple and a contributing author for the HTML5 Cookbook. She’s also a guest writer for Web Standards Sherpa.net magazine and MIX Online.

In addition to loving all things web, Emily is passionate about community building and knowledge sharing. She co-founded and co-manages Webuquerque, the New Mexico Adobe User Group for Web Professionals, and is a co-host of the The ExpressionEngine Podcast. Emily also speaks at conferences and events all over the country, including SXSW, MIX, In Control, Voices That Matter, New Mexico Technology Council, InterLab and the University of New Mexico.

Find Emily on: