Chapter 4: Media Queries

For most of my career, I’ve been a staunch proponent of non-fixed layouts. Flexible or completely fluid, it didn’t matter: I felt that building some measure of fluidity into our designs better prepared them for the changes inherent to the web: changes in the user’s browser window size, in display or device resolution. What’s more, I’d often use words like “future-proof” and “device-agnostic” when describing the need for this flexibility. Often while standing alone at parties.

But at some point, everything breaks.

As flexible as the Robot site is right now, it’s not completely bulletproof. Sure, its fluid grid makes it pretty resilient to changes in window size and screen resolution—much more so than a fixed layout would. But even slight changes to the size and shape of the browser window will cause our layout to warp, bend, and possibly break outright.

Here’s the thing, though: that’s okay.

Let the healing begin

As painful as it might be, let’s look at some of the areas where our design breaks as it reshapes itself. By identifying the problems we’re facing, we’ll be in a better position to apply the needed fixes. Even if we shed a tear or three in the process.

Since we’re working with a flexible layout, we can simply resize the browser window to a few different widths. Now, this is no substitute for actually testing our work on separate devices. But it allows us to quickly assess how our design handles several different resolution ranges, and simulate how users on capable phones, tablets, or other devices might experience our design.

A question of emphasis

Let’s begin by bringing the browser window in a bit, from around 1024 pixels wide to roughly 760 pixels or so (FIG 4.1). Pretty quickly, a number of problems appear.

Image of two browsers at different widths

FIG 4.1: By adjusting the size of our browser window, we can get a quick sense of how our design performs at different resolutions.

Our initial design was all about emphasis: large, imposing headlines, a prominent lead image, and generous margins. All of which still scale inside our flexible layout—but visually speaking, the priorities have gone way off.

Look at the top of our site, where the lead image now dominates the entire page (FIG 4.2). Since we’re cropping the image with the overflow property, it isn’t scaling with the rest of our flexible grid. What’s more, the subject of the image, our beloved robot, is actually getting pretty severely clipped. So we’re left with an image that’s not only huge, but barely comprehensible. Fantastic.

Screenshot from a medium-width web browser showing some issues with the design at the smaller width

FIG 4.2: It’s not exactly sunshine and puppies at the top of our design. Whatever that means.

Sitting in the shadow of that gigantic graphic, our logo has scaled down to a nearly microscopic size. And what little padding we enjoyed between the navigation and the lead image has been lost, making the entire masthead feel claustrophobic.

As much as I hate to say it, our visual hierarchy is reduced to shambles as soon as we move slightly below the resolution we originally designed for.

Miniature grid, monster problems

And that’s not the worst of it. If we bring the browser window in a bit more to around 600 pixels—the width of a small browser window, or of newer tablet computers held in portrait mode—the headaches just keep coming (FIG 4.3). At the top of the screen, our visual hierarchy’s still a mess: the lead image is now cropped to the point of incoherence, and our poor logo is even more of a thumbnail. But now our primary navigation is wrapping in a fairly embarrassing manner. Surely we can do better than that?

Screenshot of a web browser at a narrow width demonstrating wrapping of the navigational elements

FIG 4.3: Every visitor to our site will absolutely love this broken-looking navigation. No, trust me. They totally will.

Moving down the page, our blog is really starting to suffer (FIG 4.4). Where the two-column layout once provided easy access to some additional information, it now makes content in each column feel constricted. In particular, the article’s lines are uncomfortably short, making for a decidedly awful reading experience. And the photo set within our blog entry looks inconsequential, the content of the picture almost hard to discern.

Screenshot of a narrow web browser demonstrating that text is compressed horizontally

FIG 4.4: Reading this entry / feels like scanning a haiku: / painfully short lines.

Finally, to conclude our little sideshow of tears, the photo module at the bottom of the page is probably the worst of all (FIG 4.5). You thought the image in our blog entry was bad? These photos are comically small, and nearly indecipherable. The generous margins we initially used to frame those pictures now seem wildly out of proportion, drowning our photos in a sea of whitespace.

Screenshot of a narrow web browser showing problematic amounts of whitespace between internal images

FIG 4.5: Tiny pictures, monstrous margins. A match made in . . . well, somewhere not great.

Widescreen woes

Our problems aren’t isolated to the smaller end of the resolution spectrum, however. If we maximize our browser window, a whole new slew of design issues present themselves.

The intro (FIG 4.6) doesn’t look awful, but the image is now smaller than the space allotted for it. That aside, things don’t look terrible up top—far from ideal, I admit, but not utterly abysmal either. In general, our flexible grid looks okay up there.

Screenshot of a very wide web browser demonstrating too much width in the design

FIG 4.6: That intro is just uncomfortably wide.

So let’s quash those good feelings by scrolling down to look at the blog (FIG 4.7). Remember how clipped our entry’s lines felt in the smaller window? I’m almost missing those cramped spaces, because these lines are just frighteningly long: the width of that article column is entirely too generous at this level. As much as my eye loves to spend hours circling back to the beginning of the next line I’m supposed to read, there has to be a better way.

Screenshot of a wide web browser showing that line-length is too long and images are too small

FIG 4.7: Moving down the page, the blog doesn’t fare quite so well. Long lines, tiny images, sad Ethan.

And finally, our photo gallery completely dominates the bottom of the page (FIG 4.8). The images themselves look fine, but they’re cartoonishly large. In fact, on my monitor there’s no hint of any content above or below the module. Is this really the best way to present this information to our readers?

Screenshot of the top half of a web page on a large screen showing too-large images and no indication of additional content below the fold

FIG 4.8: These images are, to use a technical term, large ’n‘ chunky.

The problem at hand

We’ve identified a host of visual problems. But there’s a larger issue coming into focus. As we move beyond the resolution for which it was originally designed, our grid becomes a liability to our content. Its proportions constrict our content at smaller resolutions, and isolate it in a sea of whitespace at higher ones.

This isn’t a problem unique to flexible layouts, however. No design, fixed or fluid, scales well beyond the context for which it was originally designed.

So how can we create a design that can adapt to changes in screen resolution and viewport dimensions? How can our page optimize itself for the myriad browsers and devices that access it?

In other words, how can our designs become more responsive?

Slouching toward responsiveness

Thankfully, the W3C has been wrestling with this question for some time. To better understand the solution they eventually presented, it’s worth reviewing a bit of the backstory.

Meet the media types

Their first stab at a solution was media types, part of the CSS2 specification (http://bkaprt.com/rwd/24/). Here’s how they were first described:

On occasion, however, style sheets for different media types may share a property, but require different values for that property. For example, the “font-size” property is useful both for screen and print media. The two media types are different enough to require different values for the common property; a document will typically need a larger font on a computer screen than on paper. Therefore, it is necessary to express that a style sheet, or a section of a style sheet, applies to certain media types.

Okay, yeah. That’s a bit obtuse, isn’t it? Let’s try it in non-robot terms.

Ever written a print stylesheet (http://bkaprt.com/rwd/25/)? Then you’re already familiar with the concept of designing for different kinds of media. The ideal browsing experience couldn’t differ more between desktop browsers and printers, or between handheld devices and speaking browsers. To address this the W3C created a list of media types (http://bkaprt.com/rwd/26/), attempting to classify each browser or device under a broad, media-specific category. The recognized media types are: all, braille, embossed, handheld, print, projection, screen, speech, tty, and tv.

Some of these media types, like print or screen, or perhaps even projection, are probably ones you’ve used before. Perhaps others like embossed (for paged braille printers) or speech (for speaking browsers and interfaces) seem new. But all of these media types were created so that we could better design for each type of browser or device, by conditionally loading CSS tailored for each. So a screen-based device would ignore CSS loaded with the print media type, and vice versa. And for style rules meant to apply to all devices, the specification created the all supergroup.

In practice, that meant customizing the media attribute of a link:

<link rel="stylesheet" href="global.css" media="all" />
<link rel="stylesheet" href="main.css" media="screen" />
<link rel="stylesheet" href="paper.css" media="print" />

Or perhaps creating an @media block in your stylesheet, and associating it with a particular media type:

@media screen {
  body {
    font-size: 100%;
  }
}

@media print {
  body {
    font-size: 15pt;
  }
}

In each case, the specification suggests the browser would identify itself as belonging to one of the media types. (“I’m a desktop browser! I belong to the screen media type.” “I smell like ink cartridges and toner: I’m print media.” “I’m your video game console’s browser: I’m media tv.” And so on.) Upon loading the page, the browser would then render only the CSS pertaining to its particular media type, and disregard the rest. And in theory, this is a fantastic idea.

Theory being, of course, the last thing hard-working web designers need.

Miscast types

Several problems with media types became evident when all these little small-screen browsers, like phones and tablets, arrived on the scene. According to the specification, designers could have targeted them simply by creating a stylesheet for the handheld media type:

The problem with this approach is, well, us—at least in part. Early mobile devices didn’t have sufficiently capable browsers so we largely ignored them, choosing instead to design compelling screen- or print-specific stylesheets. And when capable small-screen browsers finally did appear, there weren’t a lot of handheld CSS files scattered about the web. As a result, many mobile browser makers decided to default to reading screen-based stylesheets.

But what’s more, media types paint with an incredibly broad brush. Is one handheld stylesheet really suited to address the challenges of designing for an iPhone and a five year-old feature phone?

Enter the media query

Realizing some of the failings of media types, the W3C used their work on CSS3 to take another crack at the problem. The result was media queries (http://bkaprt.com/rwd/27/), an incredibly robust mechanism for identifying not only types of media, but for actually inspecting the physical characteristics of the devices and browsers that render our content.

Let’s take a look:

@media screen and (min-width: 1024px) {
  body {
    font-size: 100%;
  }
}

Now, every media query—including the one above—has two components:

  1. Each query still begins with a media type (screen), drawn from the CSS 2.1 specification’s list of approved media types (http://bkaprt.com/rwd/26/).
  2. Immediately after comes the query itself, wrapped in parentheses: (min-width: 1024px). And our query can, in turn, be split into two components: the name of a feature (min-width) and a corresponding value (1024px).

Think of a media query like a test for your browser. When a browser reads your stylesheet, the screen and (min-width: 1024px) query asks two questions: first, if it belongs to the screen media type; and if it does, if the browser’s viewport is at least 1024 pixels wide. If the browser meets both of those criteria, then the styles enclosed within the query are rendered; if not, the browser happily disregards the styles, and continues on its merry way.

Our media query above is written as part of an @media declaration, which enables us to put queries directly inside a stylesheet. But you can also place queries on link elements by inserting them into the media attribute:

Or you can attach them to @import statements:

@import url("wide.css") screen and (min-width: 1024px);

I personally prefer the @media approach since it keeps your code consolidated in a single file, while reducing the number of extraneous requests the browser has to make to your server.

But no matter how you write your queries, the result in each scenario is the same: if the browser matches the media type and meets the condition outlined in our query, it applies the enclosed CSS. Otherwise, it won’t.

Meet the features

It’s not just about testing for width and height. There are a host of features listed in the specification our queries can test. But before we dive in, it’s worth noting that the language used to describe the features can be a bit . . . dense. Here are two quick guidelines that helped me sort it out:

  1. In the spec’s language, every device has a “display area” and “rendering surface.” Clear as mud, that. But think of it this way: the browser’s viewport is the display area; the entire display is the rendering surface. So on your laptop, the display area would be your browser window; the rendering surface would be your screen. (I don’t makes the terms. I just explains ’em.)
  2. To test values above or below a certain threshold, some features accept min- and max- prefixes. A fine example is width: you can serve CSS conditionally to viewports above 1024 pixels by writing (min-width: 1024px), or below 1024 pixels with (max-width: 1024px).

Got all that? Fantastic. With those two points out of the way, let’s dive into the features the specification says we can use in our queries (http://bkaprt.com/rwd/28/) (TABLE 4.1).

TABLE 4.1: A list of the device features we can test in our media queries.

Feature Name

Definition

Has min- and max- prefixes

width

The width of the display area.

A checkmark indicating support

height

The height of the display area.

A checkmark indicating support

device-width

The width of the device’s rendering surface.

A checkmark indicating support

device-height

The height of the device’s rendering surface.

A checkmark indicating support

orientation

Accepts portrait or landscape values.

An 'x' indicating no support

aspect-ratio

Ratio of the display area’s width over its height. For example: on a desktop, you’d be able to query if the browser window is at a 16:9 aspect ratio.

A checkmark indicating support

device-aspect-ratio

Ratio of the device’s rendering surface width over its height. For example: on a desktop, you’d be able to query if the screen is at a 16:9 aspect ratio.

A checkmark indicating support

color

The number of bits per color component of the device. For example, an 8-bit color device would successfully pass a query of (color: 8). Non-color devices should return a value of 0.

A checkmark indicating support

color-index

The number of entries in the color lookup table of the output device. For example, @media screen and (min-color-index: 256).

A checkmark indicating support

monochrome

Similar to color, the monochrome feature lets us test the number of bits per pixel in a monochrome device.

A checkmark indicating support

resolution

Tests the density of the pixels in the device, such as screen and (resolution: 72dpi) or screen and (max-resolution: 300dpi).

A checkmark indicating support

scan

For tv-based browsing, measures whether the scanning process is either progressive or scan.

An 'x' indicating no support

grid

Tests whether the device is a grid-based display, like feature phones with one fixed-width font. Can be expressed simply as (grid).

An 'x' indicating no support

What’s really exciting is that we can chain multiple queries together with the and keyword:

@media screen and (min-device-width: 480px) and (orientation: landscape) { … }

This allows us to test for multiple features in a single query, creating more complex tests for the devices viewing our designs.

Know thy features

Feeling drunk with power yet? Well, I should take this opportunity to mention that not all @media-aware browsers support querying for all features outlined in the specification.

Here’s a quick example: when Apple’s iPad first launched, it shipped with media query support for orientation. That meant you could write orientation: landscape or orientation: portrait queries to conditionally serve up CSS to the device, depending on how it was being held. Cool, no? Sadly, the iPhone didn’t support the orientation query until an OS upgrade arrived a few months later. While each device allowed the user to change its orientation, the iPhone’s browser didn’t understand the queries for that particular feature.

The moral of this story? Research your target devices and browsers thoroughly for the query features they do support, and test accordingly.

But while support is still developing among modern browsers and devices, media queries already give us an incredibly broad vocabulary, one we can use to articulate how we’d like our designs to appear in various devices and browsers.

A more responsive robot

And this is why media queries are the final component of a responsive website. We’ve spent two chapters implementing our flexible, grid-based layout—but this is only our foundation. As that layout scales up or down, we can use media queries to correct any visual imperfections that crop up as the viewport reshapes itself.

What’s more, we can use media queries to optimize the display of our content to best meet the needs of the device, creating alternate layouts tailored to different resolution ranges. By conditionally loading style rules that target these ranges, media queries allow us to create pages that are more sensitive to the needs of the devices that render them.

In other words, by combining flexible layouts and media queries, we’ll finally be able to make our sites responsive.

Let’s get started.

A room with a viewport

We’ve already identified a number of stress points in our design. But before we start applying our media queries, we need to make one final tweak to our markup.

When Apple launched the iPhone in 2007, they created a new attribute value for Mobile Safari’s meta element: viewport (http://bkaprt.com/rwd/29/). Why? Well, the dimensions of the iPhone’s display is 320×480, but Mobile Safari actually displays web pages at a width of 980 pixels. If you’ve ever visited the New York Times (http://nytimes.com) on a WebKit-enabled phone (FIG 4.9), then you’ve seen this behavior in action: Mobile Safari is drawing the page upon a 980px-wide canvas, and then shrinking it to fit within your phone’s 320×480 display.

Screenshot of iPhone showing the New York Times home page at an unreadably-small font size

FIG 4.9: By default, Mobile Safari renders web content at 980px wide—even though its display is 320px wide when held in portrait mode.

Using the viewport tag allows us to control the size of that canvas, and override that default behavior: we can dictate exactly how wide the browser’s viewport should be. For example, we could set our pages at a fixed width of 320px:

<meta name="viewport" content="width=320" />

Since being introduced by Apple, a number of mobile browser makers have adopted the viewport mechanic, creating something of a de facto standard. So let’s incorporate it into our soon-to-be responsive design. But instead of declaring a fixed pixel width, we’re going to take a more resolution-agnostic approach. In the head of our HTML, let’s drop in this meta element:

<meta name="viewport" content="initial-scale=1.0, width=device-width" />

The initial-scale property sets the zoom level of the page to 1.0, or 100%, and helps ensure some consistency across small-screen, viewport-aware browsers. (For more information on how scaling works on different displays, I recommend Mozilla’s explanation: http://bkaprt.com/rwd/30/.)

But the important bit for us is the width=device-width setting, which makes the width of the browser’s viewport equal to the width of the device’s screen. So on an iPhone, for example, Mobile Safari’s layout area wouldn’t default to 980px anymore. Instead, it would be 320 pixels wide in portrait mode; in landscape, 480 pixels wide.

With this value in place, we can use max-width and min-width to look for resolution ranges below or above certain resolution thresholds, and conditionally load in CSS designed for those ranges. What’s more, this allows all query-aware browsers to take advantage of our media queries, making the design responsive for all users—whether they’re using phones, tablets, desktop computers, or laptops.

Okay, enough of my jabbering. Let’s see this in action.

Media queries in action

Image capture of the headline in an attractive presentation

FIG 4.10: Here’s our high-impact headline treatment, looking all impactful.

Remember those large, imposing headlines (FIG 4.10)? Well, here’s the CSS that currently styles them:

.main-title {
  background: #000;
  color: #FFF;
  font: normal 3.625em/0.9 "League Gothic", "Arial Narrow", Arial, sans-serif; /* 58px / 16px */
  text-transform: uppercase;
}

I’ve left out a few presentational properties, because what I’m most concerned about is just how stupidly huge those headlines are at smaller resolutions. They’re set in the stately League Gothic (http://bkaprt.com/rwd/31/), colored in white (color: #FFF) on a black background (background: #000). And in case there was any doubt that these headlines were meant to be taken very seriously, they’re displayed in uppercase through a dash of text-transform, and then sized at an imposing 3.625em, or 58px.

Now, that treatment works well enough. But as we’ve just seen, it doesn’t look great once we’ve less real estate to work with. Whether viewed in narrower browser windows or on smaller device displays, that design just doesn’t scale.

So let’s fix that.

First, we’ll create an @media block somewhere after our initial .main-title rule, one that queries for a narrower resolution range:

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

In this query, we’ve asked that the browser render the enclosed CSS only if its viewport is no wider than 768 pixels. Why 768px? Well, media query-aware phones, as well as most recent tablets, fall well beneath this threshold. Or at least, they do when held a certain way: for example, the iPad’s resolution is 768px across when held in portrait mode, but 1024px when held in landscape mode.

But since we’re using max-width, not max-device-width, narrower browser windows on your desktop or laptop will apply this “small screen”-friendly range as well. (Remember: width and height measure the viewport or browser window, whereas device-width and device-height measure the dimensions of the entire screen.)

With this query in place, we can start targeting the elements of our design that don’t scale down that well. Let’s begin by rethinking our oversized headline treatment. To do so, we’ll place a .main-title rule inside our media query, overwriting the CSS properties that are causing us headaches:

@media screen and (max-width: 768px) {
  .main-title {
  font: normal 1.5em Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, Helvetica, sans-serif; /* 24px / 16px */
  }
}

Our first .main-title rule is still applied by all browsers reading our CSS. But for narrower browser windows and devices—specifically, those no wider than 768 pixels—the second rule is applied as well, overriding its predecessor. We’ve made two changes of note here: first, we’ve set a smaller font-size on the .main-title element, changing it from 3.625em (roughly 58px) to a much smaller 1.5em, or 24px, that feels more appropriate on smaller displays.

Secondly, the typeface we were initially using for our headlines—our beloved League Gothic—doesn’t scale down very well to that size (FIG 4.11). So I’ve decided to change the font-family stack itself (Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, Helvetica, sans-serif), which feels a bit more readable (FIG 4.12).

Smaller image of the previous headline demonstrating that the font is now too small to read clearly

FIG 4.11: League Gothic, lovely though it is, shines best as display copy. But here, it’s a little too tiny.

Improved version of the previous image using a different font that is more legible at a smaller size

FIG. 4.12: Less sexy than League Gothic? Most things are. Still, it’s much more legible, and works with the design.

Now, you’ve probably noticed that we didn’t have to rewrite the other properties from the first .main-title rule. As a result, the black background color, all-caps text-transform, and white color still apply to our miniaturized headlines. Our query only overwrites the features we don’t want.

And presto: by quickly applying a media query, we’ve whipped up a headline treatment that feels much more appropriate for smaller displays (FIG 4.13).

Comparison of the headlines using both fonts with and without media-query applied

FIG 4.13: Our default headline view above, with the media query-corrected version below.

But this is just the beginning. Not only can we fine-tune our typography to respond to changes in resolution, we can also tackle our larger design problems as well.

Thinking in miniature

In fact, let’s begin by building on our new media query, and make a slight change to our page’s layout. Remember our flexible #page container from Chapter 2? Here’s what its CSS currently looks like:

#page {
  margin: 36px auto;
  width: 90%;
}

Our container’s currently set to 90% of the browser window, and centered horizontally (margin: 36px auto). Works great, but let’s add a rule inside our existing media query to tweak its behavior once we start falling below our initial resolution:

@media screen and (max-width: 768px) {
  #page {
    position: relative;
    margin: 20px;
    width: auto;
  }
}

Below 768px, we’re instructing the #page element to occupy the full width of the browser window, save for a fixed 20px-wide margin around its edges. A minor change, but this will afford us a bit more space at smaller screen resolutions.

With our container sorted, we can turn our attention to the content area.

@media screen and (max-width: 768px) {
  #page {
    margin: 20px;
    width: auto;
   }

  .welcome,
  .blog,
  .gallery {
    margin: 0 0 30px;
    width: auto;
  }
}

This new rule selects the three top-level content modules—our introduction (.welcome), the blog (.blog), and photo gallery (.gallery)—and disables their horizontal margins, making them occupy the full width of #page.

And just like that, we’ve linearized our page’s layout, making it prime for reading on a smaller screen (FIG 4.14). Can I get a high five?

Screenshot of a web browser at a medium width showing a too-large image in the header

FIG 4.14: Our content’s been linearized with two extra rules. Neat! But there’s something amiss . . .

…no? What’s that, you say? There’s still a freakishly oversized image at the top of our page (FIG 4.15)?

Detail of the previous image providing a close-up of the too-large header image

FIG 4.15: . . . specifically, that intro image still needs work.

Well, okay. I suppose we can clean that up. If it’s really bothering you, I mean. But before we do, it’s probably worth taking a quick look at the markup for that lead image, designed to be part of a (yet-to-be-implemented) slideshow module.

<div class="welcome section">
  <div class="slides">
    <div class="figure">
      <b><img src="img/slide-robot.jpg" alt="" /></b>
      <div class="figcaption">…</div>
    </div><!-- /end .figure -->

    <ul class="slide-nav">
      <li><a class="prev" href="#">Previous</a></li>
      <li><a class="next" href="#">Next</a></li>
    </ul>
  </div><!-- /end .slides -->

   <div class="main">
   <h1 class="main-title">You can never be  
     too&#160;sure.</h1>
   </div><!-- /end .main -->
</div><!-- /end .welcome.section -->

There’s a fair bit of HTML here, but basically we’ve created a .welcome module to contain our image as well as the introductory text that follows it (.main). Our image is part of a .figure block, with the img itself wrapped in a b element, which will act as a kind of “hook” for our CSS.

Feel a bit crufty to you? I can see where you’re coming from. But that b element, silly though it might appear, actually handles a fair bit of layout for us. Here’s the relevant CSS:

.slides .figure b {
  display: block;
  overflow: hidden;
  margin-bottom: 0;
  width: 112.272727%; /* 741px / 660px */
}

.slides .figure b img {
  display: block;
  max-width: inherit;
}

First, we’ve set overflow to hidden on the b element, creating a container that will crop any oversized content. But currently, our flexible images will simply resize themselves as the b element does, preventing that nice crop effect. So we’ve disabled the max-width: 100% scaling on our slideshow images (max-width: inherit). As a result, our big robot picture will simply get cropped if it’s wider than the b element that contains it.

You might have noticed that the width of our b element is actually larger than 100%. We’ve actually used our old target ÷ context = result formula to create an element larger than the .welcome module, allowing the enclosed image to extend a bit off to the right.

But as my luck would have it, none of these effects work especially well at lower resolutions. (Related: I have awful luck.) So let’s add a bit more to the end of our media query:

@media screen and (max-width: 768px) {
  .slides .figure b {
    width: auto;
}

  .slides .figure b img {
    max-width: 100%;
  }
}

The first rule sets the width of our b container to auto, making it the same width as its container. The second rule actually reinstates the max-width: 100% behavior we discussed in Chapter 3, once again making the image expand and contract as its container does. Taken together, these two simple little rules do quite a bit, bringing our unruly image back in line with its container and, by extension, the rest of our design (FIG 4.16). I don’t know about you, but I’m already breathing a sigh of relief.

Screenshot of the revised header image at a more appropriate size

FIG 4.16: Our image has snapped into place. Relief: I feel it.

Still, there’s one more item we should tend to before putting our feet up. See our navigation up top? It’s still feeling incredibly cramped. What’s more, if we bring our viewport in even slightly, some decidedly un-awesome wrapping starts to occur (FIG 4.17).

Screenshot of the navigational menu on a medium-width web browser showing that the Contact Us item has wrapped to the next line

FIG 4.17: “Contact Us,” why do you hate us so?

The masthead markup is fairly straightforward:

<h1 class="logo">
 <a href="/">
   <i><img src="logo.png" alt="Robot or Not?" /></i>
 </a>
</h1>

<ul class="nav nav-primary">
 <li id="nav-blog"><a href="#">The &#8217;Bot Blog</a>
   </li>
 <li id="nav-rated"><a href="#">Top Rated</a></li>
 <li id="nav-droids"><a href="#">Droids of the Day</a>
   </li>
 <li id="nav-contact"><a href="#">Contact Us</a></li>
</ul><!-- /end ul.nav.nav-primary -->

That’s right: we’ve marked up our logo with an h1, and an unordered list for the navigation. And, continuing in my oh-so-imaginative streak, they’ve been classed as .logo and .nav-primary, respectively. But what about the CSS?

.logo {
  background: #C52618 url("logo-bg.jpg");
  float: left;
  width: 16.875%; /* 162px / 960px */
}

.nav-primary {
  background: #5E140D url("nav-bg.jpg");
  padding: 1.2em 1em 1em;
}

.nav-primary li {
  display: inline;
}

The styles are fairly modest. We’re applying background images to both elements, but there’s not much to the layout itself: we’re floating the image to the left, causing it to overlap the navigation. And the individual list items inside our .nav-primary list are simply set to display: inline. Still, it works—at least until our page becomes narrow enough to cause our inline elements to wrap.

Into a media query we go:

@media screen and (max-width: 768px) {
  .logo {
    float: none;
    margin: 0 auto 20px;
    position: relative;
  }

  .nav-primary {
    margin-bottom: 20px;
    text-align: center;
  }
}

What we’ve done is to disable the float we’d initially set on our .logo, and instead centered it horizontally above our menu. And .nav-primary has been set to text-align: center, which centers our navigation items within it. Now as modifications go, these are pretty minor—the change, however, is fairly noticeable (FIG 4.18). Both the logo and our primary navigation are isolated on their own rows, with the proper priority accorded to each.

Screenshot of a revised header on a narrow web browser showing a revised layout that fits horizontally

FIG 4.18: We can dramatically reorient the masthead at smaller resolutions, giving both our logo and the navigation a bit more room to breathe.

Personally, I’m pretty pleased with the way this looks—but we’re not in the clear yet. Glancing over at the navigation, it looks like things are fairly tight at the moment: there’s just not a lot of space left for our navigation items. In fact, if we bring in our screen by even a tiny amount, we’re again facing some unseemly line wrapping (FIG 4.19).

Screenshot of an even-narrower web browser that demonstrates some unattractive wrapping of the Contact Us menu item

FIG 4.19: Okay, this is starting to get silly.

(I appear to be on some sort of personal crusade against wrapping text. I don’t know why.)

We’ve uncovered another breaking point, one that isn’t fixed by simply moving the logo up to its own row. So let’s create another media query, one primed to deal with just this contingency:

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

@media screen and (max-width: 520px) {
  .nav-primary {
    float: left;
    width: 100%;
  }

  .nav-primary li {
    clear: left;
    float: left;
    width: 48%;
  }

  li#nav-rated,
  li#nav-contact {
    clear: right;
    float: right;
  }

  .nav-primary a {
    display: block;
    padding: 0.45em;
  }
}

For even smaller screens—specifically, those narrower than 520 pixels—we’ve floated each li inside of .nav-primary, choosing to float: right the second and fourth menu items. The end result is a two-by-two grid of our navigation items, one that’s more resilient to changes in viewport size than our display: inline approach (FIG 4.20).

Screenshot of a revision of the top navigational area putting the elements into two columns

FIG 4.20: I probably shouldn’t tell you how excited I am that our navigation grid is considerably more resilient to resolution changes. So I won’t.

It’s worth pointing out that we didn’t have to rewrite any of the rules from our previous query (screen and (max-width: 768px) ) in this one. That’s because screens that meet our new “narrower than 520px” requirement also meet the “narrower than 768px” requirement. In other words, rules from both queries are applied at the smallest end of the resolution spectrum. As a result, our second query only needs to concern itself with the design problems unique to viewports no wider than 520px.

And there we are (FIG 4.21). With some additional tweaking to the internals of our page, we’ve finally got a design that responds to the context it’s viewed in. We’re no longer locked in to the grid, layout, or type we originally designed for one specific resolution range. When layered on top of our flexible layout, media queries allow us to address the design problems that result from those shrinking viewports.

Three images of the design at web browser, tablet, and phone width

FIG 4.21: Our responsive design is shaping up beautifully, scaling on—and beyond—the desktop.

This layout goes to eleven

But responsive web design isn’t just about making designs accessible to smaller screens. You might recall that our design had a significant number of issues when it was viewed in a maximized browser window: images grew to unseemly sizes while lines of text became uncomfortably long, our grid stretched beyond the limits of usefulness (FIGs 4.6–4.8). Now, we could impose some sort of outer limit on our design, perhaps with a max-width set in ems or pixels. But let’s instead treat this as an opportunity to design for another resolution range.

First, we’ll begin by introducing another media query to do just that:

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

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

@media screen and (min-width: 1200px) {
  
}

Our first media query set a resolution ceiling of 768 pixels: in other words, devices and browser windows wider than that max-width limit would simply ignore the enclosed CSS. We quickly followed that up with another query for an even narrower range of 520px, once again using max-width to do so.

For our next query, we’re instead using min-width to set 1200px as a baseline width requirement for all incoming browsers and devices. If they’re wider than 1200 pixels, then they’ll apply the enclosed styles; otherwise, they’ll simply ignore the CSS, and go blithely about their business.

So let’s roll up our sleeves and set to work on a widescreen-friendly layout:

@media screen and (min-width: 1200px) {
  .welcome,
  .blog,
  .gallery {
    width: 49.375%;
  }

  .welcome,
  .gallery {
    float: right;
    margin: 0 0 40px;
  }

  .blog {
    float: left;
    margin: 0 0 20px;
  }
}

In the live Robot site (http://responsivewebdesign.com/robot), you’ll see a bunch of other changes that occur on this widescreen layout. But these three rules are really the critical ones. We’re taking our three main content modules (.welcome, .blog, and .gallery), and setting them to roughly half (49.375%) the width of the entire page. Then, we’re floating the .welcome and .gallery modules off to the right, and the blog to the left. The result? A design that’s perfectly primed for reading on larger displays (FIG 4.22). Our over-long line lengths have been reined in, and the blog—the key piece of content—has been brought higher on the page, making it considerably more accessible.

Screenshot of the design on a wide web browser showing the final layout

FIG 4.22: We’ve revisited our design, considering how widescreen readers might best experience it—and all with a quick media query.

In other words, our responsive design is finished.

A note about compatibility

After covering media queries for not a few pages, I suppose we should briefly quash a few dreams—I mean, um, we should probably talk about browser support.

The good news? Media queries enjoy remarkably broad support in modern desktop browsers. Opera has supported media queries since version 9.5, Firefox 3.5 and above supports them, as do WebKit-based desktop browsers like Safari 3+ and Chrome. Even Internet Explorer 9 (http://bkaprt.com/rwd/32/) supports media queries (http://bkaprt.com/rwd/33/)! Somebody pinch me.

And moving beyond the desktop, things are also looking good for media queries. WebKit-based mobile browsers, such as Mobile Safari, HP’s webOS, and Android’s browser all support media queries. And as reported by Peter-Paul Koch (http://bkaprt.com/rwd/34/), Opera Mobile and Opera Mini are on the @media bandwagon, as are Mozilla’s forays into mobile browsing. And with Windows Phone due to get IE9 in 2011 (http://bkaprt.com/rwd/35/), we’re facing a browser landscape that enjoys widespread support for media queries, which is incredibly exciting.

But sadly, “widespread” doesn’t mean “universal.” In desktop-based browsers older than the version numbers listed above, we’re out of luck. And yes, Internet Explorer doesn’t provide native media query support in versions 8 and below—so that means the (ahem) venerable IE6 is still a very real problem. And while many modern small screen devices offer decent support, some widely used browsers don’t understand media queries, like IE Mobile and those on older BlackBerrys (http://bkaprt.com/rwd/36/).

So things are far from rosy. But that doesn’t mean that responsive layouts are a pipe dream, however. First and foremost, there are a number of JavaScript-based solutions that patch older browsers’ lack of support. The descriptively-named css3-mediaqueries.js library (http://bkaprt.com/rwd/37/) offers to do just that, described as a solution “to make IE5+, Firefox 1+ and Safari 2 transparently parse, test, and apply CSS3 Media Queries.” It’s very much an early release, and one that hasn’t seen a lot of active development, but I can say that it’s worked quite well for me.

More recently, I’ve been using a script called respond.js (http://bkaprt.com/rwd/38/), a nimble little library developed by Scott Jehl. Where css3-mediaqueries.js is incredibly feature-rich, almost exhaustively so, Respond simply patches support for min-width and max-width queries in older browsers. And that works perfectly for most of the queries I write these days. Now, it’s worth mentioning that respond.js relies on a slight hack to work as quickly as it does, requiring designers to add a specially formatted CSS comment at the end of every media query, like so:

@media screen and (max-width: 768px) {
  …
}/*/mediaquery*/

@media screen and (max-width: 520px) {
  
}/*/mediaquery*/

@media screen and (min-width: 1200px) {
  
}/*/mediaquery*/

Why the extra comment? Well, css3-mediaqueries.js dedicates a lot of code to understanding how style sheets are structured: it can open up our CSS, and immediately tell the difference between a curly brace that’s ending a CSS rule, and the final one of an @media block. Respond doesn’t care about all that: instead, by looking for that little comment, it can grab our queries faster than most other scripts out there.

In fact, by adding that comment to the end of the Robot site’s queries, and dropping the respond.js library into the head of our page, we’ve now got a responsive layout working beautifully in older, query-blind browsers like Internet Explorer 7 (FIG 4.23).

Three screenshots of the design in Internet Explorer showing different layouts based on size

FIG 4.23: With our JavaScript patch in place, older browsers like IE now have some semblance of support for media queries.

Now, I’m not one to rely on JavaScript, and I suggest you take the same approach. We can quote stats at each other until we’re blue in the face, but there’s simply no guarantee that a user will have JavaScript available in their browser. They might be working on a desktop or laptop that’s locked down by draconian IT security measures. And once we start looking beyond the desktop, to mobile phones and other devices, JavaScript support is notoriously scant, bordering on nonexistent in many devices.

In the hopes of addressing those issues, we’ll spend some time in Chapter 5 discussing less JavaScript-reliant workarounds. But ultimately, it’s completely understandable if JavaScript-based patches don’t appeal to you. However, that only highlights the need to build your responsive design atop a flexible foundation, ensuring your design has some measure of device- and resolution-independence.

Why go flexible?

If you’ll permit me one fanboyish outburst: media queries are downright awesome. They let us conditionally serve up CSS based on the capabilities of the device rendering our sites, allowing us to more fully tailor our design to our users’ reading environment.

However, media queries alone do not a responsive design make. A truly responsive design begins with a flexible layout, with media queries layered upon that non-fixed foundation. There are a number of arguments for this, most notably that a flexible layout provides a rich fallback for JavaScript- and @media-blind devices and browsers.

But that’s not the only reason. The software company 37signals recently began experimenting with a responsive design for one of their applications, and had this to say (http://bkaprt.com/rwd/39/):

As it turned out, making the layout work on a variety of devices was just a matter of adding a few CSS media queries to the finished product. The key to making it easy was that the layout was already liquid, so optimizing it for small screens meant collapsing a few margins to maximize space and tweaking the sidebar layout in the cases where the screen is too narrow to show two columns.

In other words, starting from a flexible foundation means we have less code to produce. When working with media queries, fixed-width layouts often need to be re-coded at every resolution breakpoint, whereas a design built with percentages, not pixels, maintains its proportions from one resolution to the next. As we’ve seen in this chapter, we can selectively remove or change the properties at each breakpoint, optimizing our layout with a few quick edits.

What’s more, a flexible layout is better prepared for devices that haven’t yet launched. A year ago, mentioning “tablet” would conjure up images of the iPad in the listener’s mind. But now, seven inch tablets like Samsung’s Galaxy Tab are beginning to ship, and devices like the Kindle and Nook are also carrying fantastic little browsers. We simply can’t keep up with the different resolutions entering the marketplace. A flexible foundation allows us to step back from targeting individual resolutions, and better prepare our designs for devices that haven’t even been imagined yet.

Establish constraints as needed

With that said, nobody knows your design—and its users—better than you do. If you feel that placing a max-width on an element will help it maintain its integrity, go right ahead. Here’s 37signals describing their responsive experiments again (http://bkaprt.com/rwd/39/):

The CSS max-width property seems almost forgotten in the web designer’s toolbox since it wasn’t supported by Internet Explorer 6. With that restriction lifted, it’s the perfect complement to a liquid layout, letting the content re-flow naturally at a variety of widths but not expanding to the point of absurdity where extreme line lengths make reading a chore. It’s a great compromise between liquid and fixed layouts.

I’m currently working on a responsive redesign project where a similar discussion popped up. The design has a fixed max-width of 1200px, but is completely flexible below that point. So why not make it completely fluid? Well, we’ve spent a lot of time considering how the page looks when it passes certain breakpoints. And the media queries we’ve put in place reflect that design thinking, ensuring the site is as pleasing to read on the latest build of Chrome as it is on an Android phone or the Kindle’s browser. But ultimately, we decided we didn’t have the audience to justify the time and resources required to make a compelling widescreen design. So we decided to introduce the max-width constraint.

What’s that? You’d like to see a few live examples of the marriage of max-width and media queries? Well, I guess I’d have to mention Dan Cederholm’s site (http://simplebits.com), and design agency Happy Cog’s official blog (http://cognition.happycog.com) (FIGs 4.24 and 4.25). Both are beautiful examples of this hybrid approach to flexible layouts, starting with a fluid grid that’s eventually constrained by a pixel-based max-width.

Three images of the Simplebits design on a web browser, tablet, and phone-sized screens

FIG 4.24: Dan Cederholm, the web designer’s web designer, decided to set a max-width of 960 pixels on his newly responsive redesign. And you know what? It works.

Three images of the Happy Cog blog in web browser, tablet, and phone-sized screens

FIG 4.25: Those talented scamps at Happy Cog recently launched a responsive blog design, deciding a max-width of 820 pixels was appropriate. The result? It’s purty.

Some designers prefer this method, maintaining that long line lengths are too unruly and uncomfortable to read. And frankly, they’re right—but the max-width property is only one solution to that problem. Take designer and illustrator Jon Hicks’ site (FIG 4.26), one of the first responsive redesigns launched in 2010 (http://bkaprt.com/rwd/40/).

Three images of the The Hickensian in web browser, tablet, and phone-sized screens

FIG 4.26: Jon Hicks’ responsive site is completely flexible, and a stunner at any resolution.

While there isn’t a max-width constraining his design, Jon’s instead tweaked the typography at different resolution ranges, finely tuning the leading and font-size to ensure his words are still a pleasure to read—all without placing any constraints on his design (FIG 4.27).

Sample of text at different screen sizes showing differences in typography

FIG 4.27: Instead of relying on max-width, Jon opted to adjust his typography in certain resolution ranges, which makes for a pleasing measure and line length no matter how his blog is read.

In other words, flexibility doesn’t have to be a liability. Instead, it can be another opportunity to practice our craft, to better communicate with a certain class of users, or to solve another set of problems affecting a particular type of device.

But still, these are the kinds of decisions we constantly make as designers, choosing between flexibility and control. What responsive design shows us, however, is that it doesn’t need to be a binary proposition; we can have designs founded upon a flexible layout, while still including fixed-width elements (FIG 4.28). So when and if my client decides their audience would benefit from a widescreen layout, they could easily lift the current max-width constraint, create another media query, and design a compelling experience.

Three images of the Shelf blog theme on web browser, tablet, and phone-sized screens

FIG 4.28: Jon Hicks’ responsive “Shelf” theme for WordPress and Tumblr (http://bkaprt.com/rwd/41/) has a beautifully flexible layout, but contains fixed-width containers for different kinds of entries. (Love that horizontal scrolling!)

In other words, our designs can respond to our users’ needs as quickly as we need them to.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.213.235