facebook google plus twitter
Webucator's Free Developing Mobile Websites Tutorial

Lesson: The Viewport & Media Queries

Welcome to our free Developing Mobile Websites tutorial. This tutorial is based on Webucator's Responsive Web Design Training course.

In this lesson, we'll look first at the viewport tag, which allows us to scale content for various viewport widths. We will also learn how CSS3 media queries offer fine control over style rules, allowing us to target differing browser widths and device widths to change the manner in which we present content.

Lesson Goals

  • Learn what the meta viewport tag is.
  • Learn how to use the viewport tag to control scaling of pages for devices.
  • Learn what media queries are.
  • Learn how to use media queries.
  • Learn how to use media queries to target different browser widths.
  • Learn how to use media queries to target different device widths.

The Viewport

Our Jazz Calendar site is getting better and better - our liquid design and flexible-image handling now makes the site look better on smaller viewports. But the scale of the site, when viewed on a mobile device, leaves a bit to be desired.

We'll use the viewport meta tag to control the initial zoom of the page and, more importantly, the width of the viewport in pixels.

For this demo, you will need to publish your code to a Web server to be able to view on a smartphone device or emulator. Please refer to the setup instructions for more information.

Try viewing the file MediaQueries/Demos/viewport.html on an iPhone or other smartphone device. Without the viewport tag, the size of text and other elements, when viewed on a smartphone, is pretty small:

iphone view of Jazz Calendar site, without viewport setting

Open up the file in a code editor to inspect the code. Note the presence of the line

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

in the head of the .html file and notice that it is commented out.

Now remove the HTML comment from that line and view the page again from a smartphone or emulator. With the viewport tag in place, we're now starting to get a version of the page that feels like it's designed for mobile use. Note that the page is scaled nicely to fit the mobile screen:

iphone view of Jazz Calendar site, with viewport setting

The initial-scale=1.0 code sets the initial zoom for the page at 100%. width=device-width forces the page to render at the device's width - effectively scaling the page appropriately for our Android, iPhone, or other device.

The presence of the single line

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

in the head of the .html file accomplishes this. The initial-scale=1.0 code sets the initial zoom for the page at 100%. width=device-width forces the page to render at the device's width - effectively scaling the page appropriately for our Android, iPhone, or other device.

We can control more than just the initial scale of the page with the viewport tag:

Viewport tag options
Option Use Values
width width of viewport 200 - 10000 pixels
height height of viewport 223 - 10000 pixels
minimum-scale smallest zoom 0.0 - 10.0
maximum-scale largest zoom 0.0 - 10.0
user-scalable can user scale the page? yes/no

Targeting Widths and Devices with CSS3 Media Queries

Our Jazz Calendar site is more and more flexible: we've used a percentage-based layout to scale the site independent of the browser window's size, and we've applied CSS to scale images and other fixed-width elements. But the design still doesn't hold up when the browser window gets really narrow: elements squash together, some text might need to scale or pad differently, etc. And we've not yet addressed the specific needs of users accessing our site on a mobile device - even a scaled-down version probably won't work too well on a phone.

Jazz Calendar site breaks at narrow browser width

It would be nice not just to scale the site, but to make qualitative changes to the design based on the inherent properties of the device being used to view it, and also to adjust the design at specific browser-window widths. To address this issue, we turn to the media query.

You may already be familiar with CSS media types - a CSS2 specification that offered a way to include different stylesheets based on the media type (screen, print, etc.) being employed. A print-specific stylesheet, for example, might present a page without background images, with a print-friendly font face, and with margins appropriate for printing.

CSS3 extends this concept with the media query - a way to apply CSS rules selectively based on both the type of media and the physical properties of the device (browser, phone) being used to access the page.

Each media query comprises a media type (e.g., "screen") and zero or more logical expressions - a condition evaluating to true or false based on the conditions of particular media features. We can test our user's device for viewport width, device width, orientation ("portrait" or "landscape"), and other features.

Media Query Features
Feature Possible Values Min/Max? Explanation
color int yes bits per color component
color-index int yes number of entries in color lookup table
device-aspect-ratio int/int yes aspect ratio
device-height length (pixels) yes height of the output device
device-width length (pixels) yes width of the output device
grid int no true for a grid-based device
height length (pixels) yes height of the rendering surface
monochrome int yes bits per pixel in a monochrome frame buffer
resolution "dpi" or "dpcm" yes resolution
scan "progressive" or "interlaced" no scanning process of "tv" media types
width length (pixels) yes width of the rendering surface

Consider a revised version of the Jazz Calendar home page: open MediaQueries/Demos/noborder.html and MediaQueries/Demos/css/noborder.css in your file editor. Employing the min-width query, we create a page where:

  1. The graphic border between the two columns shows only when the browser is at least 768px wide.
  2. The left-column gig listings line up two-across when the browser is wider than 768px; one-across when narrower than 768px.

The key here are the media queries. The following code says "include the background image only if the width of the browser is at least 768 pixels."

@media screen and (min-width: 768px) { #main { width:93.75%; margin:0 auto 5.888888% auto; background: #c0cbd0 url('../images/bg_main.png') repeat-y 62.888888% 0; } }

The screenshot below shows the Jazz Calendar site at a browser width of 800 pixels. Note that the graphic background shows:

screenshot - Jazz Calendar site with border

The next screenshot shows the Jazz Calendar site at a browser width of 765 pixels. The graphic background is no longer visible:

screenshot - Jazz Calendar site without border

Adding Media Queries for Pickup Soccer

Duration: 20 to 30 minutes.

Let's use media queries to fix a few things on the Pickup Soccer site. The top (white) nav has never worked well once the browser window is resized too small (it slides under the logo when the container runs out of room to float it right). Let's change the top nav as such:

soccer top nav

Also, the game listings get a bit difficult to read when the browser gets too narrow. Let's change this to move the titles under the images when the browser gets narrow:

soccer games titles under images

  1. Open MediaQueries/Exercises/topnavandtitles/css/style.css in your file editor.
  2. Add a viewport tag to index.html.
  3. Update CSS to unfloat the top nav at widths below 600px.
  4. Update CSS so that, at browser-window widths below 960px, the titles for the game listing fall below (instead of to the right of) the thumbnail photos.

Solution:

MediaQueries/Solutions/topnavandtitles/css/style.css

Code Explanation

We use media queries to effect these changes. A query targeting a max-width of 600 pixels unfloats the top nav and adds borders. Another set of queries, targeting a browser width of 960 pixels, unfloats the .game images and modifies the h3 titles' size.

Also, notice that we added an extra CSS rule to clear every other floated .game element:

#maincontent .game:nth-of-type(odd) {
	clear:both;
}

Because each game element has a different height, we might find that the single, last item is pushed right - instead of, as we would expect, aligning left as the bottom-most element - because the item above it is too tall. We use nth-of-type(odd) to clear the floating for each odd element; for CSS nth-of-type, the first element has index 1.

Linearizing the Layout

As the browser narrows, it might make sense to slide the right sidebar under the left main column - a common strategy for shrinking a two-column design into the more narrow confines of a smartphone. As the screenshot below shows, the columns get pretty slim when the browser is narrowed too much, to the point where just a few words show on each line of the right sidebar:

Jazz Calendar screenshot - columns shrink too narrow

Let's add a few more media queries to handle browser widths of less than 520px - an arbitrary breakpoint, chosen here because it seems to make sense in the context of our page.

The page MediaQueries/Demos/linearize.html now behaves in the same manner as the previous example (graphic border and two-across gig listings disappear at browser-window widths less than 768px), but now the sidebar stops floating right (and thus slides under the main content) at widths less than 520px. Open the page in a browser and change the browser's width to check it out. Be sure to examine the media queries in MediaQueries/Demos/css/linearize.css - specifically the media queries that govern the #maincontent and #sidebar elements at widths less than 520 pixels:

@media screen and (max-width: 520px) {
	#main #maincontent {
		float:none;
		width:92%;
	}
}

@media screen and (max-width: 520px) {
	#main #sidebar {
		width:92%;
		float:none;
	}
}

Linearizing the Pickup Soccer Site

Duration: 20 to 30 minutes.

In this exercise, you'll update the Pickup Soccer site again, this time presenting the sidebar under the main column at widths under 520px, as shown:

soccer site screenshot

  1. Open MediaQueries/Exercises/sidebarnotfloated/index.html and MediaQueries/Exercises/sidebarnotfloated/css/style.css.
  2. Add a viewport tag to index.html.
  3. Update CSS to show the main nav without floating right and with modified background and text colors for browser widths under 520 pixels.
  4. Update CSS to unfloat the sidebar, sliding it under the main column at widths under 520px.

Solution:

MediaQueries/Solutions/sidebarnotfloated/index.html



  Soccer Pickup
  
  
  




  

Upcoming Games

Barry Park

Sundays, around 2pm; near the back of the largest field

Lakeside Park

Sundays, around 2pm; near the back of the largest field

Schiller Elementary School

Sundays, around 2pm; near the back of the largest field

Central High

Sundays, around 2pm; near the back of the largest field

Adams Park

Sundays, around 2pm; near the back of the largest field

Soccer Pickup: Your guide to finding a game.

Solution:

MediaQueries/Solutions/sidebarnotfloated/css/style.css
body {
	font-family:Georgia,serif;
	background-image:url('../images/bg_grass.jpg');
}

a {
	text-decoration:none;
	color:#4040AD;
}

a:hover {
	text-decoration:underline;
}

#container {
	width:85%;
	margin:0 auto;
	background: #fff url('../images/bg_soccerballs.png') repeat-y 65.520833% 0;
}

@media screen and (max-width: 520px) {
	#container {
		background: #fff;
	}
}

header {
	background-color:#d0b462;
}

header #logo {
	margin:1.0416666% 0 1.0416666% 3.75%;
}

nav {
	padding:1.0416666% 3.75% 1.0416666% 3.75%;
	float:right;
}

@media screen and (max-width: 520px) {
	nav {
		float:none;
		background:#ccc;
	}
}

nav ul {
	display:inline;
}

nav ul li {
	display:inline;
}

nav ul li a {
	color:#fff;
	text-decoration:none;
	margin-left:20px;
}

@media screen and (max-width: 520px) {
	nav ul li a {
		color:#000;
	}
}

#maincontent {
	width:61.7708333333%;
	padding:1.0416666% 0 3.75% 3.75%;
	float:left;
}

@media screen and (max-width: 520px) {
	#maincontent {
		width:96.25%;
		padding:1.0416666% 0 3.75% 3.75%;
		float:none;
	}
}

#maincontent h1 {
	font-size:36px;
	margin:5px 0 20px 0;
}

#maincontent .game {
	float:left;
	width:47.892074199%;
	line-height:14px;
	font-size:14px;
	margin:0.8431703204%;
}

#maincontent .game:nth-of-type(odd) {
    clear:both;
}

#maincontent .game img {
	float:left;
	margin:0 2.86% 0 0;
	max-width:100%;
}

#maincontent iframe {
	max-width:100%;
}

#sidebar {
	width:26.9791666667%;
	float:right;
	padding:3.75%;
	color:#333;
	line-height:20px;
}

@media screen and (max-width: 520px) {
	#sidebar {
		width:96.25%;
		padding:3.75% 0 3.75% 3.75%;
		float:none;
		clear:left;
		background:#ccc;
	}
}

#sidebar h3 {
	font-style:italic;
	font-size:20px;
	margin:0 0 5px 0;
}

#footerinfo {
	clear: both;
	background-color:#151570;
	padding:1.0416666% 0 1.0416666% 3.75%;
}
#footerinfo p {
	color:#fff;
}

We use a media query to unfloat the main nav at widths under 520 pixels:

@media screen and (max-width: 520px) {
	nav {
		float:none;
		background:#ccc;
	}
}

Similarly, we use several more media queries to prevent the floating left and right of the main content and sidebar elements, respectively, forcing the sidebar to fall under the main content when the browser resizes to less than 520 pixels.

@media screen and (max-width: 520px) {
	nav {
		float:none;
		background:#ccc;
	}
}

@media screen and (max-width: 520px) {
	#maincontent {
		width:96.25%;
		padding:0.96% 0 3.75% 3.75%;
		float:none;
	}
}

Using max-device-width

We'll now use media queries to target the properties of the device being used to view our page. The property max-device-width allows us to target the physical properties of the viewport - max-device-width: 480px, for instance, applies not when the browser window is resized to less than 480px, but rather when the device itself - a smartphone, say - has a viewport less than 480px wide.

To view your code on a smartphone or emulator, you will need to publish to a Web server; please refer to the setup instructions for more information on how to do this.

Consider the file MediaQueries/Demos/devicewidth.html. View this latest version of the Jazz Calendar home page on an iPhone, Android, or other smartphone device or on an emulator - you'll see that we've used media queries to selectively apply style rules just for devices with a maximum viewport width less than 480px:

Jazz Calendar site - iphone view

  1. The top nav is listed vertically, with some extra top/bottom padding and bottom borders.
  2. As on the small-width browser design, we don't float the sidebar right - rather, it slides under the main content area.
  3. Similarly, the gig listings appear one-on-each-line, rather than two-across, and with a black border at bottom.

Pickup Soccer - For Phones

Duration: 20 to 30 minutes.

In this exercise, you will update the Pickup Soccer site for mobile devices - we'll use media queries to display the site like this on a phone:

Pickup Soccer site - phone view

  1. Open MediaQueries/Exercises/devicewidth/index.html and MediaQueries/Exercises/devicewidth/css/style.css in your file editor.
  2. Add a viewport tag to index.html.
  3. Write CSS to display the main nav below the header (rather than floated within).
  4. Write CSS to display the sidebar below the main column (rather than floated to the right of).

Solution:

MediaQueries/Solutions/devicewidth/css/style.css
body {
	font-family:Georgia,serif;
	background-image:url('../images/bg_grass.jpg');
}

a {
	text-decoration:none;
	color:#4040AD;
}

a:hover {
	text-decoration:underline;
}

#container {
	width:85%;
	margin:0 auto;
	background: #fff url('../images/bg_soccerballs.png') repeat-y 65.520833% 0;
}

@media screen and (max-device-width: 480px) {
	#container {
		background: #fff;
	}
}

header {
	background-color:#d0b462;
}

header #logo {
	margin:1.0416666% 0 1.0416666% 3.75%;
}

nav {
	padding:1.0416666% 3.75% 1.0416666% 3.75%;
	float:right;
}

@media screen and (max-device-width: 480px) {
	nav {
		float:none;
		background:#ccc;
	}
}

nav ul {
	display:inline;
}

nav ul li {
	display:inline;
}

nav ul li a {
	color:#fff;
	text-decoration:none;
	margin-left:20px;
}

@media screen and (max-device-width: 480px) {
	nav ul li a {
		color:#000;
		margin-left:10px;
	}
}

#maincontent {
	width:61.7708333333%;
	padding:1.0416666% 0 3.75% 3.75%;
	float:left;
}

@media screen and (max-device-width: 480px) {
	#maincontent {
		width:96.25%;
		padding:1.0416666% 0 3.75% 3.75%;
		float:none;
	}
}

#maincontent h1 {
	font-size:36px;
	margin:5px 0 20px 0;
}

#maincontent .game {
	float:left;
	width:47.892074199%;
	line-height:14px;
	font-size:14px;
	margin:0.8431703204%;
}

#maincontent .game:nth-of-type(odd) {
    clear:both;
}

#maincontent .game img {
	float:left;
	margin:0 2.86% 0 0;
	max-width:100%;
}

#maincontent iframe {
	max-width:100%;
}

#sidebar {
	width:26.9791666667%;
	float:right;
	padding:3.75%;
	color:#333;
	line-height:20px;
}

@media screen and (max-device-width: 480px) {
	#sidebar {
		width:96.25%;
		padding:3.75% 0 3.75% 3.75%;
		float:none;
		clear:left;
		background:#ccc;
	}
}

#sidebar h3 {
	font-style:italic;
	font-size:20px;
	margin:0 0 5px 0;
}

#footerinfo {
	clear: both;
	background-color:#151570;
	padding:1.0416666% 0 1.0416666% 3.75%;
}
#footerinfo p {
	color:#fff;
}

We construct queries with max-device-width: 480px to target narrow devices, unfloating the nav:

@media screen and (max-device-width: 480px) {
	nav {
		float:none;
		background:#ccc;
	}
}

#maincontent:

@media screen and (max-device-width: 480px) {
	#maincontent {
		width:96.25%;
		padding:0.96% 0 3.75% 3.75%;
		float:none;
	}
}

and #sidebar elements:

@media screen and (max-device-width: 480px) {
	#sidebar {
		width:96.25%;
		padding:3.75% 0 3.75% 3.75%;
		float:none;
		clear:left;
		background:#ccc;
	}
}