Responsive Web Design with CSS3 - Video, Graphics, and Glitz - HTML5: The Missing Manual Matthew MacDonald (2013)

HTML5: The Missing Manual Matthew MacDonald (2013)

Part 2. Video, Graphics, and Glitz

Chapter 7. Responsive Web Design with CSS3

When web designers first started putting their content into HTML pages, they faced a challenge. Whereas print designers could rely on certain assumptions about how their documents would be arranged on paper and how they would be read by their audiences, the online world was loose and lawless. Depending on the user’s browser (and personal preferences), the same HTML page might appear wedged in a tiny window or floating in a giant one. This made complex layouts risky. A layout that looked perfect in one window could easily turn into an awkward and ungainly mess when viewed in a window with different proportions.

Today, this variability has only increased. Not only do web designers need to think about different sizes of browser windows on desktop computers, but they also need to accommodate different sizes of devices, like tablets and smartphones. And at the same time, website layouts have become more intricate, with most sites now composed of menus, navigation aids, sidebars, and so on. If your goal is to create a single website that can shift gracefully between different viewing contexts, these details present a significant challenge.

Because web designers have long since outsourced the layout and formatting work of their web pages to CSS, it makes sense for CSS to provide the solution for this problem. Fortunately, CSS3 has the perfect tool: a feature called media queries, which lets your website seamlessly switch from one set of styles to another depending on the window size or the viewing device.

Media queries are an essential technique for mobile web development. But even if you don’t expect any visitors to surf your site on a smartphone, media queries will still help you ensure that your layout adapts itself to the viewer—for example, dropping an extra column when there’s no space to show it comfortably, or moving the navigation links from the top of a page to its side. This sort of adaptation is part of a wildly popular web design philosophy called responsive design, which you’ll explore in this chapter.

Responsive Design: The Basics

The problem of varying window sizes has been around since the dawn of the Web. Over the years, web designers have cooked up a variety of complementary techniques—some elegant, some messy—to cope with the challenges of responsive design.

Before you learn how to use media queries, it’s important to consider the following traditional tactics. All of them are still important today—but, as you’ll see, they don’t form a complete solution on their own. Once you recognize their limits, you’ll understand how CSS3 patches the gaps.

Fluid Layout

The simplest solution to the problem of resizing windows is to make a proportional layout—one that simply sucks up the available space, no matter how large or small it is.

Creating a proportional layout is easy enough in theory. The basic principle is to carve up your page into columns using percentage sizes instead of pixel sizes. Say, for example, you have a two-column layout like this:

<body>

<div class="leftColumn">

...

</div>

<div class="rightColumn">

...

</div>

</body>

The style rules for a fixed layout might look like this:

.leftColumn {

width: 275px;

float: left;

}

.rightColumn {

width: 685px;

float: left;

}

body {

margin: 0px;

}

But the style rules for a proportionately sized layout would look like this:

.leftColumn {

width: 28.6%;

float: left;

}

.rightColumn {

width: 71.4%;

float: left;

}

body {

margin: 0px;

}

Here, the left column has a width of 28.6%, so it takes 28.6% of the width of its container, which is the <body> element. In this example, the <body> element has no margins, so it takes up the full width of the browser window, and the left column gets 28.6% of that.

As you would expect, the percentages of the two columns combined add up to exactly 100%, filling the page. No matter what the size of the browser window, the columns expand or shrink to match. Proportional layouts are also called fluid layouts, because the content flows seamlessly into whatever space is available.

NOTE

In this example, the left column width of 28.6% is calculated by dividing the fixed width of the column (275 pixels) into the fixed width of the entire layout (which, previously, was set at the relatively common default width of 960 pixels). Because most layouts are initially planned using fixed widths, web developers are accustomed to using this sort of calculation when they createfluid layouts.

Of course, it’s not enough to adjust column sizes alone. You also need to think about margins, padding, and borders. When novice web developers create their first fluid layouts, they often leave in fixed margins and padding (using pixel values), while sizing their columns proportionately. As a result, the columns can occupy only the space that’s left over after the margins are subtracted. However, the column width percentages are calculated according to the full page width, without taking the margins into account. This discrepancy can lead to problems in narrow windows, when the fixed-width margins crowd out the proportional columns.

For example, imagine you create styles like this:

.leftColumn {

width: 27%;

margin: 5px;

float: left;

}

.rightColumn {

width: 68%;

margin: 5px;

float: left;

}

These two columns occupy a combined 95%, leaving an extra 5% for the margin space. This is enough for mid- to large-sized windows, but if you size the window small enough, the leftover 5% can’t accommodate the fixed margin space. To see this problem in action, simply give each column a different background color using the background property and then try resizing the window, as shown in Figure 7-1.

Proportionally sized columns and fixed margins don’t mix. Make the window too small, and the margins crowd out the second column.

Figure 7-1. Proportionally sized columns and fixed margins don’t mix. Make the window too small, and the margins crowd out the second column.

To fix this problem, any margins you add between proportional columns must also use proportional sizing. So if the columns leave 5% of the page width unclaimed, you can use that for your margins. Split it into three 1.66% sections—one for the left edge of the window, one for the right edge of the window, and one for the space between the columns, like this:

.leftColumn {

width: 27%;

margin-left: 1.66%;

margin-right: 1.66%;

background: #FFFFCC;

float: left;

}

.rightColumn {

width: 68%;

margin-right: 1.66%;

background: #CCFFCC;

float: left;

}

Figure 7-2 shows the solution, with both margins and columns sized proportionally using percentages.

As long as all the horizontal measurements are done proportionally with percentages, your page’s layout will scale to any size.

Figure 7-2. As long as all the horizontal measurements are done proportionally with percentages, your page’s layout will scale to any size.

Depending on the effect you want, you may find that proportional margins don’t look quite right. If you don’t want your margins to change based on the size of the web browser window, you can use a workaround. For example, you can place another element inside one of your proportional columns and give that element its own fixed margins or padding. Because this element is placed inside the top-level layout that you’ve already established, and because your layout is fully proportional, it will fit snugly into any window size.

Borders present a similar problem. If you add borders to your columns, the extra space they require will break your layout in the same way as the fixed margins shown in Figure 7-1. In this situation, you can’t solve the problem with proportional measurements, because borders don’t accept percentage widths. Instead, the easiest solution is to use the workaround suggested above: Add a <div> element inside your proportional column, and apply the border to the <div>. This time-honored technique makes your markup a bit messier (because you need an extra layer of layout), but it ensures that your layout works at any size.

FEATURE FROM THE FUTURE: CSS3 BOX-SIZING AND CALC()

The layout problems you’ve touched on in this section are common—so common that CSS3 is brimming with potential solutions. Here are two of the most promising (although not perfect, as you’ll see).

§ Box-sizing. Ordinarily, borders are added to the outside of elements, which means you need to subtract the border space from your layout calculations. But CSS3 adds a new box-sizing property that, if set to border-box, puts the border on the inside of your box. The border looks the same, but the size calculation is different. For example, it means that a 67%-wide column stays 67% wide, no matter how thick its border.

§ The calc() function. If you need to combine proportional and fixed measurements, you can ask CSS3 to do the calculations for you—and use the results in your layout—thanks to the nifty calc() function. For example, imagine you need to create a column that’s 67% wide, less 5px of margin space. Careless web developers might fudge the issue by sizing the column down to 65% (causing the inconsistent spacing issue shown in Figure 7-1). But with CSS3 you can set the width property to calc(67%-5px), which makes sure your column mops up exactly all of the available space—and not a pixel more.

Unfortunately, in both cases the cure may not be much better than the disease. The box-sizing setting fails on IE 7, and requires the vendor-specific -moz- prefix (Browser-Specific Styles with Vendor Prefixes) on Firefox. The calc() function fails on IE 7, IE 8, and the pre-Chrome Android browser, and older versions of Safari require the -webkit- prefix. There are polyfills that can smooth out these issues, but for now it’s easier to avoid these features altogether until more people inch forward to newer, more modern browsers.

Fluid Images

Achieving a multicolumn, proportional layout is the first step in responsive design. However, there’s plenty more to occupy yourself with when you begin to consider the content in those columns.

One issue is images. Ordinarily, image boxes are sized to fit their content—in other words, the exact pixel dimensions of your picture file. However, this arrangement can lead to a problem in small-sized windows. If there’s not enough room to accommodate the picture, it will spill out of its column and sprawl over other elements, obscuring them and generally looking sloppy.

The solution to this annoyance is simple. Cap each image at the maximum width of its container, with a style rule that looks like this:

img {

max-width: 100%;

}

As always, the 100% is relative to the element’s container. In this case, that’s the column that contains the image, not the whole page. Now your image can grow until it reaches its full size or until it meets the boundaries of its container, whichever comes first (Figure 7-3).

Without fluid images, any picture can run amok (top). But limit the width to match the container, and images get exactly the right size (bottom).

Figure 7-3. Without fluid images, any picture can run amok (top). But limit the width to match the container, and images get exactly the right size (bottom).

TIP

If you decide to add a margin around your image, make sure the percentages you use for the margin-left, margin-right, and max-width total 100% (and not more).

One limitation of fluid images is that the browser needs to download the full-sized image file no matter what size the image is displayed at. This wastes a small amount of time and bandwidth, which is inconvenient for mobile devices. Sadly, CSS can’t correct this problem on its own. But there are other potential solutions that attempt to deal with this issue using some combination of server-side code, web services, and JavaScript libraries. If you’re serving up an image-heavy site to large numbers of mobile users, you may want to consider these techniques, which are discussed in a Smashing Magazine article at http://tinyurl.com/responsive-img (but most web developers won’t bother). Happily, there is a way to solve the analogous but more serious problem of video sizes on mobile devices—see the box on Media Queries for Video.

Fluid Typography

Now that you have a fluid layout with properly sized pictures, it’s time to turn your attention to the text in each column. Casual web developers pick an attractive fixed size for their text (using pixel measurements) and leave it at that. However, such hard-coded sizes break the responsive layout model, because text that’s properly sized on a desktop display will be vanishingly tiny on mobile devices. And while website readers can always zoom in to see small text, the goal of responsive design is to make a page that fits any window without requiring excessive zooming and side-to-side scrolling.

Once again, the solution involves avoiding using fixed units of measurement like pixels and points. Instead, you want to set your text sizes relatively, using percentages or em units. The em unit, named after the letter M, is the most popular choice.

NOTE

The em has a long tradition of representing widths in print typography. For example, the term em dash originally referred to a dash that was the width of a capital M in the current typeface.

Percentage sizes and em units have the same result: The size of your text is adjusted relative to the browser’s default text size. If you set a text size of 110% or 1.1em, you’ll get letters that are 10% bigger than normal, unstyled text. Set a text size of 50% or 0.5em, and you’ll get half-sized characters.

Although it doesn’t matter whether you use percentages or ems, most responsive web designs follow the same convention. They set the base text size of the page to 100% (just to emphasize that this is the baseline from which all other text is sized), and then tweak that size up or down in other elements with ems:

body {

font-size: 100%

}

p {

font-size: 0.9em

}

h1 {

font-size: 2em

}

Experienced web developers don’t stop there. Instead, they use ems for all other fixed measurements in their layouts. For example, if you have a border or a bit of margin or padding space deep inside your layout, you’re better off to set it with ems than pixels. That way, these sizes are tweaked to match the size of the text. It’s a subtle adjustment, but one that creates a more polished appearance.

For example, imagine you’ve created a two-level layout that places a <div> inside your left column. You use this <div> to get the extra spacing you want around your content, without breaking the proportionally sized column layout:

<body>

<div class="leftColumn">

<div class="leftColumnContent">

...

</div>

</div>

<div class="rightColumn">

...

</div>

</body>

You could set the border, margins, and padding of your left column content <div> using pixels. Your layout would still work and it would still be fluid. But it’s even better if you use ems, as shown here:

.leftColumn {

width: 28.6%;

background: #FFFFCC;

float: left;

}

.rightColumn {

width: 71.4%;

background: #CCFFCC;

float: left;

}

.leftColumnContent {

border: 0.07em solid gray;

margin: 0.3em;

padding: 0.2em 0.3em 0.4em 0.4em;

}

NOTE

In most layouts, the chief benefit of using ems for borders, margins, and padding is that it prevents these elements from being too large in tiny windows and dominating your layout on mobile devices.

FEATURE FROM THE FUTURE: CSS3: WHEN AN EM BECOMES A REM

There’s one quirk that faces web designers when using text in complex responsive layouts. Proportionately sized text units, like ems and percentages, size their text with respect to the containing element. That’s no problem in a simple example like the one considered on Fluid Typography, because the containing element is the <body> element that holds the page, or another element that inherits the font settings of the <body> element. The headaches happen when you apply proportional sizing to multiple levels of your layout.

For example, suppose you create a <div> and give it a text size of 1.1em. Then, inside that <div> you add an <h1> heading with a size of 2em. You might expect that the heading is twice the default text size, but it’s actually twice the size of its container, which is 1.1em. That works out to a heading that’s 2.2 times the default text size.

To avoid this compounding effect, you need to be disciplined about where you apply your text sizing. Ideally, you should do it at only one layout level. However, CSS3 has a new unit that neatly solves the problem, called rems (which stands for “root em”). Essentially, a rem is a relative measurement just like an em, but with a twist: No matter where you put it, a rem is always calculated relative to the text size of the <html> element, not the text size of the containing element. Thus, 2rem is always two times the size of normal text, no matter where you apply it.

Rems have surprisingly good support—they work in every modern browser. The problem is the familiar stragglers, IE 8 and IE 7, which don’t understand rems at all. And while it’s technically possible to polyfill the gap with JavaScript (see http://tinyurl.com/rem-polyfill), most sensible web developers avoid adding yet another script simply to switch their unit system and stick to the slightly inconvenient em units for now.

Of course there’s much more to typography than the size of your typeface. To create text that remains readable on a range of displays, you need to think about line-lengths, margins, line height, and even multicolumn text (as demonstrated on Putting Text in Multiple Columns). You can’t deal with any of these issues using ordinary fluid layouts and proportional sizing. However, you can create more flexible style sheets that tweak these other details using media queries, as you’ll see shortly. But first, there’s one more consideration that you need to unravel: the automatic scaling behavior of mobile phones.

Understanding Viewports: Making Your Layout Work on a Smartphone

In theory, the two-column example you’ve seen so far can fit into any window size. But in practice there’s another complication that comes into play for small mobile devices: the size of the viewport.

Apple introduced the viewport concept so its iPhones could do a respectable job displaying the ordinary websites of the time, which didn’t use the techniques of responsive web design. Instead of showing just a tiny fragment of a large web page, mobile browsers like Safari show a zoomed-out view that fits in more content. This zoomed-out display area is called the viewport.

The viewport technique is a bit of a tradeoff. It ensures that the page looks more like it would on a desktop browser, but it also makes most ordinary text illegible. It reduces the need to scroll back and forth, but it increases the need to zoom in and out. It makes it easier for viewers to orient themselves in the page, but it prevents them from comfortably reading the content.

NOTE

Although Apple introduced the viewport feature, all other mobile developers now follow the same practice. The only difference is how big the viewport is and how much of the web page gets crammed into view at once.

If you’re creating a traditional desktop website, you don’t have to worry about the devices’ viewport settings. They’ll ensure that your site looks reasonably good on super-small mobile screens (even though mobile visitors won’t find the scaled-down site completely convenient). On the other hand, if you’re planning to go all the way with responsive design and create a true, mobile-friendly website, you need to make viewport changes. You need to tell mobile browsers not to perform their automatic viewport scaling, which you can easily do by adding the following <meta>element to the page’s <head> section:

<meta content="initial-scale=1.0" name="viewport">

This line tells mobile devices to use the true scale of your page, with no zooming out. For example, it means a modern iPhone will fit your page into a 320-pixel wide window and display that at full size. Without this scale adjustment, the iPhone will give your page a desktop-sized 980 pixels of width and then shrink that down to fit. Figure 7-4 shows the difference.

NOTE

You’re probably aware that there are plenty of online simulators that let you see what your website looks like on different mobile devices. For example, on http://mobiletest.me you can compare your site’s appearance on the latest iPhones, iPads, and Android devices. However, most simulators don’t replicate the automatic scaling behavior. In other words, when you preview your site in a simulator, it may look as though you set the initial scale to 1.0 with the <meta> element shown above. If you haven’t, you won’t get an accurate reflection of what you’ll see on the device itself, so tread with caution.

Adapting Your Layout with Media Queries

You’ve now seen how to create a fluid layout that can grow or shrink to fit any browser window. This approach guarantees that your page will fit into any window. However, it doesn’t ensure that your page will always look good.

Simple fluid layouts tend to break down at the extremes. In a very tiny window, multiple columns are compacted down to embarrassingly thin dimensions, crowding text and pictures into an unreadable jumble. In a very large window, columns become dauntingly large, and it’s hard to follow a line across the vast expanse of the page without losing your place.

Left: The iPhone’s automatic rescaling treats this fluid layout like a desktop-optimized web page. As a result, its text is unreadable without zooming.Right: Turn off the scaling, and you see your page as it truly is. The next step is to simplify the layout at small sizes using media queries.

Figure 7-4. Left: The iPhone’s automatic rescaling treats this fluid layout like a desktop-optimized web page. As a result, its text is unreadable without zooming. Right: Turn off the scaling, and you see your page as it truly is. The next step is to simplify the layout at small sizes using media queries.

One way to deal with these issues is to set limits on how far your layout can expand or contract. You can do that with the max-width and min-width properties. Expand a page beyond its maximum width, and you’ll end up with an extra margin of space on the right. Shrink a page past its minimum width, and the columns will lock into their dimensions, while the browser adds scroll bars to let you move around. Maximum and minimum width settings give you a bit of basic protection against extreme layouts. However, they also reduce the value of your responsive design. For example, if your page can’t shrink down to the dimensions of an iPhone window, it’s not much use to mobile visitors.

A better solution is to gracefully tweak the structure of the layout when your page size changes. For example, a really small window needs a streamlined layout with no sidebars or ad panels. And a really big window presents the opportunity for scaled up text or multiple columns of text (Putting Text in Multiple Columns).

Enter media queries. This CSS3 feature gives you a simple way to vary styles for different viewing settings. Used carefully, they can help you serve everything from an ultra-widescreen desktop computer to an iPhone—without altering a single line of HTML.

The Anatomy of a Media Query

Media queries work by latching onto a key detail about the device that’s viewing your page (like its size, resolution, color capabilities, and so on). Based on that information, you can apply different styles, or even swap in a completely different style sheet.

At its simplest, a media query is a separate section in your style sheet. That section starts with the word @media, followed by a condition in parentheses, and then a series of related styles in curly brackets. Here’s the basic structure:

@media (media-feature-name: value) {

/* New styles go here. */

}

A media query is similar to a block of conditional JavaScript code. If the current browser meets the condition that you’ve set out in parentheses, the styles inside come into effect. But if the browser doesn’t satisfy the condition, the styles are ignored.

NOTE

The styles that lie outside of your @media section are always applied, no matter what. The conditional media query styles are applied in addition to the other styles. For that reason, the conditional media query styles often have the job of overriding the other style settings—for example, hiding something that was previously visible, moving a section to a new location, applying new text sizes, and so on.

To use a media query, you need to know what sorts of conditions you can construct. The media query standard lets you examine various details, which it calls media features. For example, you can find out the width of the display area and then change your styles when it shrinks beyond a certain limit. Table 7-1 lists the most commonly used media features. (There are also several vendor-specific, experimental media features that aren’t supported consistently. These aren’t included in this table.)

Table 7-1. Most useful media features for building media queries

FEATURE NAME

VALUE

COMMONLY USED TO…

width

min-width

max-width

The width of the display area (or rendering surface, on a printer).

Change the layout to accommodate very narrow displays (like a smartphone) or very wide displays.

height

min-height

max-height

The height of the display area.

Change the layout to accommodate very tall or very short displays.

device-width

min-device-width

max-device-width

The full width of the screen on the current computer or device (or the full width of a page in a printout).

Adjust the layout to specifically target different devices, like smartphones.

device-height

min-device-height

max-device-height

The full height of the screen or page.

Adjust the layout to specifically target different devices, like smartphones.

orientation

One of two values: landscape or portrait.

Change the layout for different orientations on a table computer.

device-aspect-ratio

min-device-aspect-ratio

max-device-aspect-ratio

The proportions of the display area, as a ratio. For example, an aspect ratio of 1/1 is completely square.

Adjust styles to fit different window shapes (although this approach quickly gets complicated).

color

min-color

max-color

The number of color bits. For example, 1-bit color is monochrome, while modern displays typically use 24-bit color, which accommodates millions of colors.

Check for the presence of color (for example, for a printable version of a page), or assess the level of color support.

NOSTALGIA CORNER: CSS MEDIA TYPES

Interestingly, the creators of CSS took a crack at the multiple-device problem in CSS 2.1, using a feature called media types. You may already be using this standard to supply a separate style sheet for printouts:

<head>

...

<!-- Use this stylesheet to display the

page onscreen. -->

<link rel="stylesheet" media="screen"

href="styles.css">

<!-- Use this stylesheet to print the

page. -->

<link rel="stylesheet" media="print"

href="print_styles.css">

</head>

The media attribute also accepts the value handheld, which is meant for low-bandwidth, small-screen mobile devices. As a result, many modern mobile browsers ignore handheld style sheets anyway, making the media attribute a woefully inadequate tool for dealing with the wide range of web-connected devices that exists today. However, it’s still a good way to clean up printouts.

Creating a Simple Media Query

You’ll notice that most media query features have several versions, which let you set maximum or minimum limits. These limits are important, because most media queries apply to a range of values.

To use media queries, you must first choose the property you want to examine. For example, if you wanted to create a new set of styles that comes into effect for narrow windows, you’d choose the max-width setting. It’s then up to you to choose a suitable limit. For example, the following media query creates a block of conditional styles that spring into action when the width of the browser window is 480 pixels or less:

@media (max-width: 480px) {

...

}

TIP

Right now, the most popular media features are max-device-width (for creating mobile versions of your pages), max-width (for varying styles based on the current size of the browser window), and orientation (for changing your layout based on whether a tablet computer like an iPad is turned horizontally or vertically).

For a simple test, use a media query to make an obvious change. For example, this media query alters the background color of a column:

@media (max-width: 480px) {

.leftColumn {

background: lime;

}

}

Now you can check whether your media query is working. In your browser, slowly resize the browser window. As soon as the display area of the window shrinks to less than 480 pixels, the new style kicks in and the column changes to a fetching shade of lime green. All the other style properties that you’ve applied to the leftColumn class (for example, its size and positioning) stay in place, because the media query doesn’t override them.

NOTE

Browsers that don’t understand media queries, like Internet Explorer 8, will simply ignore these new styles and keep applying the original styles, no matter how big or small the browser window becomes.

If you want, you can add another media query section that overrides these rules at a still-smaller size. For example, this section will apply new rules when the browser width creeps under 250 pixels:

@media (max-width: 250px) {

...

}

Just remember that these rules are overriding everything that’s been applied so far—in other words, the cumulative set of properties that have been set by the normal styles and the media query section for under 450 pixels. If this seems too confusing, don’t worry—you’ll learn to work around it with more tightly defined media queries on More Advanced Media Query Conditions. But first, it’s time to consider a more practical example.

Building a Mobile-Friendly Layout

With media queries, you have the essential building blocks you need to create a website that looks just as respectable in a smartphone browser as a desktop browser. All you need to do is apply them.

Figure 7-5 shows a revamped example of the ApocalypseSite.html page you first saw in Chapter 2 (Deeper into Headers). The original page used a fixed layout with hard-coded column widths. The revised version uses all of the techniques explored in this chapter. It has a fluid layout with proportional sizing (Responsive Design: The Basics) that fits any window width. It uses em units for margins, padding, border widths, and text sizes, ensuring that these details are adjusted in harmony on different devices (Fluid Typography). The site header image grows or shrinks to fit the available space, and the ad image in the sidebar uses the fluid image technique to make sure it never oversteps its bounds (Fluid Images). It also uses the <meta> element fix to prevent mobile browsers from zooming out (Adapting Your Layout with Media Queries).

Behind the scenes, this page uses the best practices of responsive web design. You can peruse the complete CSS on the try-out site at .

Figure 7-5. Behind the scenes, this page uses the best practices of responsive web design. You can peruse the complete CSS on the try-out site at http://prosetech.com/html5.

In short, the new ApocalypseSite.html page is mobile-ready. However, its layout still isn’t mobile-friendly. That’s because no matter how small the two side-by-side columns compress themselves, they won’t fit cleanly in a tiny window. To correct this oversight, you need to use a media query.

Before you crack open your style sheet, you need to consider what the mobile version of your site should look like. Usually, mobile sites slim themselves down to a single column. Sidebars are either hidden completely or inserted above or below the main content. Figure 7-6 shows a cleaned-up version of the ApocalypseSite.html on an iPhone.

Here are two snapshots of the mobile version of the ApocalypseSite.html page. The page starts with a small site header, followed by the article content (left). The article links and ad block from the sidebar are placed after the article footer (right).

Figure 7-6. Here are two snapshots of the mobile version of the ApocalypseSite.html page. The page starts with a small site header, followed by the article content (left). The article links and ad block from the sidebar are placed after the article footer (right).

It’s surprisingly easy to create the mobile version of the ApocalypseSite.html page. The shrunken site header and nicely sized text happen automatically, thanks to the page’s use of fluid images and em units. The only task left for your media query is to rearrange the columns.

Initially, the two columns are defined with these two style rules:

.NavSidebar {

float: left;

width: 22%;

font-size: small;

}

.Content {

float: left;

width: 78%;

}

The sidebar is floated on the left with a width of 22%. The content is floated next to it and given a width of 78%.

Because the layout stops working at small widths, it makes sense to use the popular max-width media feature. As you learned in the previous section, max-width gets the current size of the page in the browser window. If this value is small, two columns aren’t appropriate.

Here’s the media query that removes the floats and resizes the section so the columns take the full available width:

@media (max-width: 568px) {

.NavSidebar {

float: none;

width: auto;

}

.Content {

float: none;

width: auto;

}

}

These styles are applied in addition to the normal styles you’ve already defined. Thus, you may need to reset properties you’ve already changed to their default values. In this example, the media query styles reset the float property to none, and the width property to auto (although it would work equally well if you set the width to 100%). These are the default values, but the original sidebar style changed them. You’ll also notice that the original NavSidebar style set the font size. The media query doesn’t override this detail, so it stays in place.

Technically, this media query creates styles that apply to any narrow window, regardless of whether it’s in a mobile browser or in a micro-sized window on a desktop browser. This makes perfect sense, but you can get more particular and create one set of styles for tiny desktop windows and another for mobile devices. To target tiny desktop windows, you’d use max-width, and to spot mobile devices, you’d use max-device-width, as detailed in Table 7-1.

TIP

It’s up to you when you want to switch to your simplified layout, but the 568-pixel mark is a good choice. That’s because 568 pixels is the width of your page in an iPhone when it’s turned sideways, in landscape orientation. (It works for Android devices too, as explained on Recognizing Specific Mobile Devices.)

This example needs one more adjustment. In the original version of the page, the NavSidebar section is defined before the Content section in the HTML markup. This lets you float them both on the left side, and makes sure the NavSidebar is on the left. Unfortunately, when you remove the floating behavior, the mobile version of the site is forced to show the sections in the order they appear, which means the NavSidebar appears at the top of the page, followed by the Content section underneath. This layout is a bit off-putting to mobile viewers, since they’d rather not scroll through a set of links and advertisements before they get to the meat of the page.

When faced with a challenge like this, the solution is to start by arranging your markup to suit the mobile version of the site, and then layer on extra CSS rules to create the more sophisticated multicolumn layout. This gold-standard technique is called mobile-first development.

In this example, that means putting the Content section before the NavSidebar section. This solves the problem in the mobile version of the page, but it also forces the sidebar to the right column on the full-sized version of the page. To correct this quirk, simply tweak the Content section so it floats to the right:

.Content {

float: right;

width: 78%;

}

Now the Content section returns to its place on the right, while the NavSidebar clings to the left, restoring the full-size layout shown in Figure 7-5.

At this point, you may want to consider adding another media query to also change your styles for very wide windows. For example, you could break your text into multiple columns (using the CSS properties described on Putting Text in Multiple Columns) to make sure your text remains readable.

TIP

Looking for some examples to inspire you? Try out a ready-made responsive template. There are plenty of examples on the Web. To get started, start browsing http://html5up.net, www.typeandgrids.com, or http://responsify.it.

More Advanced Media Query Conditions

Sometimes you might want to make your styles even more specific, so they depend on multiple conditions. Here’s an example:

@media (min-width: 400px) and (max-width: 700px) {

/* These styles apply to windows from 400 to 700 pixels wide. */

}

POWER USERS’ CLINIC: HIDING AND REPLACING SECTIONS

If you’re ambitious, there are many more changes you can make to differentiate the mobile version of your site from its full-size incarnation. For example, you can use the CSS display property to hide and show entire sections of your page.

Before you use this approach, consider its drawbacks. If you switch large sections of your page, you’ll be left with messy markup, which you’ll need to maintain, keep consistent, and test on different devices. Also, if your hidden sections contain images, browsers will still download them, even if they’re never shown. On a mobile device, this can become a performance drag and a waste of bandwidth.

However, there is an appropriate time to use the section-switching technique: when you need to replace a complex navigation aid or menu with a slimmer, simpler mobile version. For example, it’s common practice to give mobile users a drop-down list for navigation instead of an unwieldy tree. (There’s even a clever style technique that can convert a row of links into a drop-down list, as detailed at http://css-tricks.com/convert-menu-to-dropdown).

Sometimes, simple tricks and small alterations aren’t enough. You may want to revamp the mobile version of your site more radically. Here, you have a range of options, ranging in complexity and sophistication. At one extreme, you could create a completely separate mobile site and host it on a different web domain (as the New York Times does with its mobile site athttp://mobile.nytimes.com). This option is a lot more work, and without some sort of content management system running on your web server, you’ll never keep your mobile site in sync with your standard site. Another way is to write web server code that checks every request, figures out what web browser is on the other end, and sends the appropriate type of content. This sort of solution is great, if you have the time and skills.

A more modest approach is to use a JavaScript tool that lets you alter your pages dynamically based on the viewer. One example is Modernizr, which provides a method named Modernizr.mq() for testing media queries in your code (read about it at http://modernizr.com/docs). This approach is more powerful than media queries, but it also introduces more complexity into your page design.

This type of media query comes in handy if you want to apply several sets of mutually exclusive styles, but you don’t want the headaches of several layers of overlapping rules. Here’s an example:

/* Normal styles here */

@media (min-width: 600px) and (max-width: 700px) {

/* Override the styles for 600-700 pixel windows. */

}

@media (min-width: 400px) and (max-width: 599.99px) {

/* Override the styles for 400-600 pixel windows. */

}

@media (max-width: 399.99px) {

/* Override the styles for sub-400 pixel windows. */

}

In this case, if the browser window is 380 pixels, exactly two sets of styles will apply: the standard styles and the styles in the final @media block. Whether this approach simplifies your life or complicates it depends on what you’re trying to accomplish. If you’re using complex styles and changing them a lot, the no-overlap approach shown here is often the simplest way to go.

Notice that you have to take care that your rules don’t unexpectedly overlap. For example, if you set the maximum width of one rule to 400 pixels and the minimum width of another rule to 400 pixels, you’ll have one spot where both style settings suddenly combine. The slightly awkward solution is to use fractional values, like the 399.99 pixel measurement used in this example.

Another option is to use the not keyword. There’s no functional difference, but if the following style sheet makes more sense to you, feel free to use this approach:

/* Normal styles here */

@media (not max-width: 600px) and (max-width: 700px) {

/* Override the styles for 600-700 pixel windows. */

}

@media (not max-width: 400px) and (max-width: 600px) {

/* Override the styles for 400-600 pixel windows. */

}

@media (max-width: 400px) {

/* Override the styles for sub-400 pixel windows. */

}

In these examples, there’s still one level of style overriding to think about. That’s because every @media section starts off with the standard, no-media-query style rules. Depending on the situation, you may prefer to separate your style logic completely (for example, so a mobile device gets its own, completely independent set of styles). To do so, you need to use media queries with external style sheets, as described next.

Replacing an Entire Style Sheet

If you have simple tweaks to make, the @media block is handy, because it lets you keep all your styles together in one file. But if the changes are more significant, you may decide that it’s easier to create a whole separate style sheet. You can then use a media query to create a link to that style sheet:

<head>

<link rel="stylesheet" href="standard.css">

<link rel="stylesheet" media="(max-width: 568px)" href="small_styles.cs

s">

...

</head>

The browser will download the second style sheet (small_styles.css) with the page but won’t apply it unless the browser width falls under the maximum.

As in the previous example, the new styles will override the styles you already have in place. In some cases, you want completely separate, independent style sheets. If so, you first need to add a media query to your standard style sheet to make sure it kicks in only for large sizes:

<link rel="stylesheet" media="(min-width: 568.01px)" href="standard.css"

>

<link rel="stylesheet" media="(max-width: 568px)" href="small_styles.css">

The problem with this approach is that browsers that don’t understand media queries will ignore both style sheets. You can fix this up for old versions of Internet Explorer by adding your main style sheet again, but with conditional comments:

<link rel="stylesheet" media="(min-width: 568.01px)" href="standard.css">

<link rel="stylesheet" media="(max-width: 568px)" href="small_styles.css">

<!--[if lt IE 9]>

<link rel="stylesheet" href="standard.css">

<![endif]-->

This example still has one small blind spot. Old versions of Firefox (earlier than 3.5) don’t understand media queries and don’t use the conditionally commented IE section. You could solve the problem by detecting the browser in your code and then using JavaScript to swap in a new page, but it’s messy. Fortunately, old versions of Firefox are becoming increasingly rare.

Incidentally, you can combine media queries with the media types described in the box on CSS Media Types. When you do so, always start with the media type, and don’t put it in parentheses. For example, here’s how you could create a print-only style sheet for a specific page width:

<link rel="stylesheet" media="print and (min-width: 25cm)"

href="NormalPrintStyles.css" >

<link rel="stylesheet" media="print and (not min-width: 25cm)"

href="NarrowPrintStyles.css" >

Recognizing Specific Mobile Devices

As you’ve already learned, you can distinguish between normal computers and mobile devices by writing a media query that uses max-device-width. But what widths should you use?

If you’re looking for mobile phones, check for a max-device-width of 568 pixels. This is a good rule of thumb, since it catches current iPhone and Android phone models, whether they’re in portrait or landscape orientation:

<link rel="stylesheet" media="(max-device-width: 568px)"

href="mobile_styles.css">

If you’re a hardware geek, this rule may have raised a red flag. After all, modern mobile devices use tiny, super-high-resolution screens. For example, the iPhone 5 crams a grid of 640 x 1136 pixels into view at once. You might think you’d need larger device widths to recognize these devices. Surprisingly, though, that isn’t the case.

For example, consider the iPhone 5. It claims that it has a pixel width of 320 pixels (in portrait orientation), even though it actually has twice as many physical pixels. It uses this quirk to prevent websites from concluding that 640-pixel wide iPhone displays should receive the full desktop version of a website. Although the iPhone can certainly display such a site, its tiny pixels would make it all but impossible to read.

Most modern, high-resolution devices behave this way. They add in a fudge factor called the pixel ratio. In the iPhone (version 4 and later), every CSS pixel is two physical pixels wide, so the pixel ratio is 2. In fact, you can create a media query that matches the iPhone 4 but ignores older iPhones, using the following media query:

<link rel="stylesheet"

media="(max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)"

href="iphone4.css">

Table 7-2 lists the device widths of some popular devices. Keep in mind that there’s often a bit of pixel ratio fudgery at work. For example, all versions of the iPad report a device width of 768, even though the number of physical pixels doubled in the iPad 3.

Table 7-2. Common device widths

DEVICE

DEVICE WIDTH (IN PORTRAIT MODE)

DEVICE WIDTH (IN LANDSCAPE MODE)

Apple iPhone 4

320

480

Apple iPhone 5

320

568

Apple iPad

768

1024

Samsung Galaxy S4

360

640

Google Nexus 4

384

640

Kindle Fire

600

1024

TIP

New devices are released all the time. For current information, consult a site like www.mobitest.me/devices.

Tablets like the iPad pose a special challenge: Users can turn them to show content vertically or horizontally. And although this changes the max-width, it doesn’t alter the max-device-width. In both portrait and landscape orientation, the iPad reports a device width of 768 pixels. Fortunately, you can combine the max-device-width property with the orientation property if you want to vary styles based on the iPad’s orientation:

<link rel="stylesheet"

media="(max-device-width: 768px) and (orientation: portrait)"

href="iPad_portrait.css">

<link rel="stylesheet"

media="(max-device-width: 768px) and (orientation: landscape)"

href="iPad_landscape.css">

Of course, this rule isn’t limited to iPads. Other devices that have similar screen sizes (in this case, 768 pixels or less) will get the same style rules.

NOTE

On their own, media queries probably aren’t enough to turn a normal website into a mobile-friendly one. You’ll also need to think about the user experience. You may need to break content down into smaller pieces (so less scrolling is required) and avoid effects and interactions that are difficult to navigate with a touch interface (like pop-up menus).

GEM IN THE ROUGH: MEDIA QUERIES FOR VIDEO

One obvious difference between desktop websites and mobile websites is the way they use video. A mobile website may still include video, but it will typically use a smaller video window and a smaller media file. The reasons are obvious—not only do mobile browsers have slower, more expensive network connections to download video, but they also have less powerful hardware to play it back.

Using the media query techniques you’ve just learned, you can easily change the size of a <video> element to suit a mobile user. However, it’s not as easy to take care of the crucial second step and link to a slimmed-down video file.

HTML5 has a solution: It adds a media attribute directly to the <source> element. As you learned in Chapter 5, the <source> element specifies the media file a <video> element should play. By adding the media attribute, you can limit certain media files to certain device types.

Here’s an example that hands the butterfly_mobile.mp4 file out to small-screened devices. Other devices get butterfly.mp4 or butterfly.ogv, depending on which video format they support.

<video controls width="400" height="300">

<source src="butterfly_mobile.mp4"

type="video/mp4"

media="(max-device-width: 480px)">

<source src="butterfly.mp4"

type="video/mp4">

<source src="butterfly.ogv"

type="video/ogg">

</video>

It’s still up to you to encode a separate copy of your video for mobile users. Encoding tools usually have device-specific profiles that can help you out. For example, they might have an option for encoding “iPad video.” It’s also still up to you to make sure that you use the right media format for your device (usually, that will be H.264) and supply video formats for every other browser.