This codelab is part of the Developing Progressive Web Apps training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.

For complete details about the course, see the Developing Progressive Web Apps overview.

Introduction

This lab shows you how to style your website content to make it responsive.

What you'll learn

What you should know

What you will need

Download or clone the pwa-training-labs repository from github and install the LTS version of Node.js, if needed.

If you don't have a preferred local development server, install the Node.js http-server package:

npm install http-server -g

Navigate into the responsive-design-lab/app/ directory and start the server:

cd responsive-design-lab/app
http-server -p 8080 -a localhost -c 0

You can terminate the server at any time with Ctrl-c.

Open your browser and navigate to localhost:8080/.

Note: Unregister any service workers and clear all service worker caches for localhost so that they do not interfere with the lab. In Chrome DevTools, you can achieve this by clicking Clear site data from the Clear storage section of the Application tab.

If you have a text editor that lets you open a project, open the responsive-design-lab/app/ folder. This will make it easier to stay organized. Otherwise, open the folder in your computer's file system. The app/ folder is where you will be building the lab.

This folder contains:

Return to the app in the browser. Try shrinking the window width to below 500px and notice that the content doesn't respond well.

Open developer tools and enable device mode in your browser. This mode simulates the behavior of your app on a mobile device. Notice that the page is zoomed out to fit the fixed-width content on the screen. This is not a good experience because the content will likely be too small for most users, forcing them to zoom and pan.

Replace TODO 3 in index.html with the following tag:

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

Save the file. Refresh the page in the browser and check the page in device mode. Notice the page is no longer zoomed out and the scale of the content matches the scale on a desktop device. If the content behaves unexpectedly in the device emulator, toggle in and out of device mode to reset it.

Note: Device emulation gives you a close approximation as to how your site will look on a mobile device, but to get the full picture you should always test your site on real devices. You can learn more about debugging Android devices on Chrome and Firefox.

Explanation

A meta viewport tag gives the browser instructions on how to control the page's dimensions and scaling. The width property controls the size of the viewport. It can be set to a specific number of pixels (for example, width=500) or to the special value device-width, which is the width of the screen in CSS pixels at a scale of 100%. (There are corresponding height and device-height values, which can be useful for pages with elements that change size or position based on the viewport height.)

The initial-scale property controls the zoom level when the page is first loaded. Setting initial scale improves the experience, but the content still overflows past the edge of the screen. We'll fix this in the next step.

For more information

Replace TODO 4 in styles/main.css with the following code:

@media screen and (max-width: 48rem) {
  .container .col {
    width: 95%;
  }
}

Save the file. Disable device mode in the browser and refresh the page. Try shrinking the window width. Notice that the content switches to a single column layout at the specified width. Re-enable device mode and observe that the content responds to fit the device width.

Explanation

To make sure that the text is readable we use a media query when the browser's width becomes 48rem (768 pixels at browser's default font size or 48 times the default font size in the user's browser). See When to use Em vs Rem for a good explanation of why rem is a good choice for relative units. When the media query is triggered we change the layout from three columns to one column by changing the width of each of the three divs to fill the page.

The Flexible Box Layout Module (Flexbox) is a useful and easy-to-use tool for making your content responsive. Flexbox lets us accomplish the same result as in the previous steps, but it takes care of any spacing calculations for us and provides a bunch of ready-to-use CSS properties for structuring content.

Comment out existing rules in CSS

Comment out all of the rules in styles/main.css by wrapping them in /* and */. We will make these our fallback rules for when Flexbox is not supported in the Flexbox as progressive enhancement section.

Add Flexbox layout

Replace TODO 5.2 in styles/main.css with the following code:

.container {
  display: -webkit-box;  /* OLD - iOS 6-, Safari 3.1-6 */
  display: -ms-flexbox;  /* TWEENER - IE 10 */
  display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
  background: #eee;  
  overflow: auto;
}

.container .col {
  flex: 1;
  padding: 1rem;
}

Save the code and refresh index.html in your browser. Disable device mode in the browser and refresh the page. If you make your browser window narrower, the columns grow thinner until only one of them remains visible. We'll fix this with media queries in the next exercise.

Explanation

The first rule defines the container div as the flex container. This enables a flex context for all its direct children. We are mixing old and new syntax for including Flexbox to get broader support (see For more information for details).

The second rule uses the .col class to create our equal width flex children. Setting the first argument of the flex property to 1 for all divs with class col divides the remaining space evenly between them. This is more convenient than calculating and setting the relative width ourselves.

For more information

Optional: Set different relative widths

Use the nth-child pseudo-class to set the relative widths of the first two columns to 1 and the third to 1.5. You must use the flex property to set the relative widths for each column. For example, the selector for the first column would look like this:

.container .col:nth-child(1)

Use media queries with Flexbox

Replace TODO 5.4 in styles/main.css with the code below:

@media screen and (max-width: 48rem) {
  .container {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    flex-flow: column;
  }
}

Save the code and refresh index.html in your browser. Now if you shrink the browser width, the content reorganizes into one column.

Explanation

When the media query is triggered we change the layout from three-column to one-column by setting the flex-flow property to column. This accomplishes the same result as the media query we added in step 5. Flexbox provides lots of other properties like flex-flow that let you easily structure, re-order, and justify your content so that it responds well in any context.

As Flexbox is a relatively new technology, we should include fallbacks in our CSS.

Add Modernizr

Modernizr is a feature detection tool that simplifies testing for Flexbox support.

Replace TODO 6.1 in index.html with the code to include the custom Modernizr build:

<script src="modernizr-custom.js"></script>

Explanation

We include a Modernizr build at the top of index.html, which tests for Flexbox support. This runs the test on page-load and appends the class flexbox to the <html> element if the browser supports Flexbox. Otherwise, it appends a no-flexbox class to the <html> element. In the next section we add these classes to the CSS.

Note: If we were using the flex-wrap property of Flexbox, we would need to add a separate Modernizr detector just for this feature. Older versions of some browsers partially support Flexbox, and do not include this feature.

Use Flexbox progressively

Let's use the flexbox and no-flexbox classes in the CSS to provide fallback rules when Flexbox is not supported.

Now in styles/main.css, add .no-flexbox in front of each rule that we commented out:

.no-flexbox .container {
  background: #eee;
  overflow: auto;
}

.no-flexbox .container .col {
    width: 27%;
    padding: 30px 3.15% 0;
    float: left;
}

@media screen and (max-width: 48rem) {
  .no-flexbox .container .col {
    width: 95%;
  }
}

In the same file, add .flexbox in front of the rest of the rules:

.flexbox .container {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  background: #eee;
  overflow: auto;
}

.flexbox .container .col {
  flex: 1;
  padding: 1rem;
}

@media screen and (max-width: 48rem) {
    .flexbox .container {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        flex-flow: column;
    }
}

Remember to add .flexbox to the rules for the individual columns if you completed the optional step 5.3.

Save the code and refresh index.html in the browser. The page should look the same as before, but now it works well in any browser on any device. If you have a browser that doesn't support Flexbox, you can test the fallback rules by opening index.html in that browser.

For more information

You have learned to style your content to make it responsive. Using media queries, you can change the layout of your content based on the window or screen size of the user's device.

What we've covered

Resources

Learn more about the basics of responsive design

Learn more about Flexbox as a progressive enhancement

Learn about libraries for responsive CSS

Learn more about using media queries

To see all the codelabs in the PWA training course, visit the PWA training course codelabs landing page.