Responsive web design basics

As the number of mobile phone users on the internet increases, it has become more and more important for web designers to lay out content in ways that work well for a variety of screen sizes. Responsive web design, originally defined by Ethan Marcotte in A List Apart, is a design strategy that responds to users' needs and their devices' capabilities by changing a site's layout to suit the device being used. For example, a responsive site might show content in a single-column view on a phone, two columns on a tablet, and three or four columns on a desktop computer.

As the screen gets wider, the widget changes shape in response.

Because internet-capable devices have so many possible screen sizes, it's important for your site to adapt to any existing or future screen size. Modern responsive design also accounts for modes of interaction such as touch screens. The goal is to optimize the experience for everyone.

Set the viewport

Pages optimized for a variety of devices must include a meta viewport tag in the head of the document. This tag tells the browser how to control the page's dimensions and scaling.

To try to provide the best experience, mobile browsers render the page at a desktop screen width (usually about 980px, though this varies across devices), and then try to make the content look better by increasing font sizes and scaling the content to fit the screen. This can make fonts look inconsistent and require users to zoom in to see and interact with the content.

<!DOCTYPE html>
<html lang="en">
  <head>
    …
    <meta name="viewport" content="width=device-width, initial-scale=1">
    …
  </head>
  …

Using the meta viewport value width=device-width tells the page to match the screen's width in device-independent pixels (DIP), a standard visual pixel unit (which can be made up of many physical pixels on a high-density screen). This lets the page reflow content to match different screen sizes.

Screenshot of a
    page with the text hard to read because it's very zoomed out.
A page without the viewport meta tag loads very zoomed out, making the text hard to read. See this example on Glitch.
Screenshot of
    the same page with the text at a size that can be read.
With the viewport meta tag set, you can read the page without zooming in. See this example on Glitch.

Some browsers keep the page's width constant when rotating to landscape mode, and zoom to fill the screen instead of reflowing. Adding the value initial-scale=1 tells browsers to set a 1:1 relationship between CSS pixels and device-independent pixels regardless of device orientation, letting the page take advantage of the full landscape width.

The Does not have a <meta name="viewport"> tag with width or initial-scale Lighthouse audit can help you automate the process of making sure your HTML documents use the viewport meta tag correctly.

Size content to the viewport

On both desktop and mobile devices, users are used to scrolling websites vertically but not horizontally. Forcing the user to scroll horizontally or to zoom out to see the whole page causes a poor user experience.

When developing a mobile site with a meta viewport tag, it's common to accidentally create page content that doesn't quite fit within the specified viewport. For example, an image displayed wider than the viewport can cause horizontal scrolling. To prevent this, adjust your content to fit inside the viewport.

The Content is not sized correctly for the viewport Lighthouse audit can help you automate the process of detecting overflowing content.

Images

An image with fixed dimensions causes the page to scroll if it's larger than the viewport. We recommend giving all images a max-width of 100%, which shrinks images to fit the available space while preventing them from stretching beyond their initial size.

In most cases, you can do this by adding the following to your style sheet:

img {
  max-width: 100%;
  display: block;
}

Add the dimensions of the image to the img element

Even when you set max-width: 100%, we still recommend adding width and height attributes to your <img> tags so the browser can reserve space for images before they load. This helps prevent layout shifts.

Layout

Because screen dimensions and width in CSS pixels vary widely between devices (for example, between phones and tablets, and even between different phones), content shouldn't rely on a particular viewport width to render well.

In the past, this required setting layout elements in percentages. Using pixel measurements requires the user to scroll horizontally on small screens:

Screenshot of a two-column layout with most of the second column outside the viewport
A floated layout using pixels. See this example on Glitch.

Using percentages instead makes the columns narrower on smaller screens, because each column always takes up the same percentage of the screen width:

Modern CSS layout techniques such as Flexbox, Grid Layout, and Multicol make creating these flexible grids much easier.

Flexbox

Use Flexbox when you have a set of items of different sizes and you want them to fit comfortably in a row or multiple rows, with smaller items taking up less space and larger ones taking more space.

.items {
  display: flex;
  justify-content: space-between;
}

You can use Flexbox to display items as a single row, or wrapped onto multiple rows as the available space decreases.

Read more about Flexbox.

CSS Grid Layout

CSS Grid Layout creates flexible grids. You can improve the earlier floated example using use grid layout and the fr unit, which represents a portion of the available space in the container.

.container {
  display: grid;
  grid-template-columns: 1fr 3fr;
}

You can also use Grid Layout to create regular grid layouts with as many items as can fit. The number of available tracks is reduced as the screen size decreases. The following demo shows a grid containing as many cards as fit on each row, with a minimum size of 200px.

Read more about CSS Grid Layout

Multiple-column layout

For some types of layout, you can use Multiple-column Layout (Multicol), which creates responsive numbers of columns with the column-width property. In the following demo, the page adds columns when there's room for another 200px column.

Read more about Multicol

Use CSS media queries for responsiveness

Sometimes you might need to make more extensive changes to your layout to support certain screen sizes than the techniques described previously allow. This is where media queries become useful.

Media queries are simple filters that you can apply to CSS styles, to change those styles based on the types of device rendering the content. They can also change styling based on device features including width, height, orientation, and whether the device is being used as a touchscreen.

To provide different styles for printing, you can target an output type and include a style sheet for print styles:

<!DOCTYPE html>
<html lang="en">
  <head>
    …
    <link rel="stylesheet" href="print.css" media="print">
    …
  </head>
  …

You can also use a media query to include print styles in your main style sheet:

@media print {
  /* print styles go here */
}

For responsive web design, the most common queries are for device features, so you can customize your layout for touchscreens or smaller screens.

Media queries based on viewport size

Media queries let you create a responsive experience that applies specific styles to specific screen size. Queries for screen size can test for the following things:

  • width (min-width, max-width)
  • height (min-height, max-height)
  • orientation
  • aspect-ratio

All of these features have excellent browser support. For more details, including browser support information, see width, height, orientation, and aspect-ratio on MDN.

Media queries based on device capability

Given the range of devices available, developers can't assume that every large device is a regular desktop or laptop computer, or that every small device uses a touchscreen. Some newer additions to the media queries specification let you test for features such as the type of pointer used to interact with the device and whether the user can hold a pointer over elements.

  • hover
  • pointer
  • any-hover
  • any-pointer

Try viewing this demo on different devices, such as a regular desktop computer and a phone or tablet.

These newer features have good support in all modern browsers. Find out more on the MDN pages for hover, any-hover, pointer, and any-pointer.

Use any-hover and any-pointer

The features any-hover and any-pointer test if the user can hold a pointer over elements (often called hovering), or use a pointer at all, even if it's not the primary way they interact with their device. Be very careful when using these, for example to avoid forcing a touchscreen user to switch to a mouse. However, any-hover and any-pointer can be useful if it's important to determine what kind of device a user has. For example, a laptop with a touchscreen and trackpad should match coarse and fine pointers, in addition to the ability to hover.

How to choose breakpoints

Don't define breakpoints based on device classes, or any product, brand name, or operating system. This makes your code difficult to maintain. Instead, let the content determine how its layout changes to fit the container.

Pick major breakpoints by starting small, then working up

Design the content to fit on a small screen size first, then expand the screen until a breakpoint becomes necessary. This lets you minimize the number of breakpoints on your page and optimize them based on content.

The following example walks through the weather forecast widget example at the beginning of this page. The first step is to make the forecast look good on a small screen:

Screenshot of
    a weather app at a mobile width
The app at a narrow width.

Next, resize the browser until there's too much whitespace between the elements to make the widget look good. The decision is subjective, but more than 600px is certainly too wide.

Screenshot of
    a weather app with wide gaps between items
At this size, the app's layout should probably change.

To insert a breakpoint at 600px, create two media queries at the end of your CSS for the component: one to use when the browser is 600px or narrower, and one for when it's wider than 600px.

@media (max-width: 600px) {

}

@media (min-width: 601px) {

}

Finally, refactor the CSS. Inside the media query for a max-width of 600px, add the CSS which is only for small screens. Inside the media query for a min-width of 601px add CSS for larger screens.

Pick minor breakpoints when necessary

In addition to choosing major breakpoints when layout changes significantly, it's also helpful to adjust for minor changes. For example, between major breakpoints it can be helpful to adjust the margins or padding on an element, or increase the font size to make it feel more natural in the layout.

This example follows the same pattern as the previous one, starting with optimizing smaller screen layouts. First, boost the font when the viewport width is greater than 360px. After that, when there's enough space, you can separate the high and low temperatures so they're on the same line, and make the weather icons larger.

@media (min-width: 360px) {
  body {
    font-size: 1.0em;
  }
}

@media (min-width: 500px) {
  .seven-day-fc .temp-low,
  .seven-day-fc .temp-high {
    display: inline-block;
    width: 45%;
  }

  .seven-day-fc .seven-day-temp {
    margin-left: 5%;
  }

  .seven-day-fc .icon {
    width: 64px;
    height: 64px;
  }
}

For large screens, we recommend limiting the maximum width of the forecast panel so it doesn't use the whole screen width.

@media (min-width: 700px) {
  .weather-forecast {
    width: 700px;
  }
}

Optimize text for reading

Classic readability theory suggests that an ideal column should contain 70 to 80 characters per line (about 8 to 10 words in English). Consider adding a breakpoint every time the width of a text block grows past about 10 words.

Screenshot of a
    page of text on a mobile device
Text on a mobile device.
Screenshot of a a page of text on a desktop browser
The same text in a desktop browser with a breakpoint added to constrain the line length.

In this example, the Roboto font at 1em produces 10 words per line on the smaller screen, but larger screens need a breakpoint. In this case, if the browser width is greater than 575px, the ideal content width is 550px.

@media (min-width: 575px) {
  article {
    width: 550px;
    margin-left: auto;
    margin-right: auto;
  }
}

Avoid hiding content (:#avoid-hiding-content)

Be careful when choosing what content to hide or show depending on screen size. Don't hide content just because you can't fit it on the screen. Screen size doesn't predict what a user might want to see. For example, removing the pollen count from the weather forecast could be a serious issue for springtime allergy sufferers who need that information to decide whether they can go outside.

View media query breakpoints in Chrome DevTools

After you set up your media query breakpoints, check how they affect your site's appearance. You could resize your browser window to trigger the breakpoints, but Chrome DevTools has a built-in feature that shows how a page looks under different breakpoints.

Screenshot of DevTools with our weather app open and a width of 822 pixels selected.
DevTools showing the weather app at a wider viewport size.
Screenshot of DevTools with our weather app open and a width of 436 pixels selected.
DevTools showing the weather app at a narrower viewport size.

To view your page under different breakpoints:

  1. Open DevTools.
  2. Turn on Device Mode. This opens in responsive mode by default.
  3. To see your media queries, open the Device Mode menu and select Show media queries. This shows your breakpoints as colored bars above your page.
  4. Click one of the bars to view your page while that media query is active. Right-click a bar to jump to that media query's definition.