Chapter 05 of 09Part 2 · Layout
Responsive web design, from phone to wide screen
One page that works on every screen: the viewport tag, mobile first media queries, fluid type and images that fit.
10 minBy Zuzo StudioUpdated
In this chapter you will
- set up the viewport so phones show your page at its real width
- write mobile first media queries with breakpoints taken from your content
- size type, spacing and images so they adapt smoothly to any screen
Before you startThis builds on Flexbox vs grid: laying out a page.
The same page gets opened on a 360 pixel phone held upright, a tablet on its side, a laptop and a 27 inch monitor. Responsive web design is the practice of building one page that works on all of them, rather than a separate "mobile site". It is less about a few breakpoints and more about a way of writing CSS: let things flex by default, then step in only where the content needs it. You already have two of the tools from the flexbox and grid chapter. This chapter adds the rest: the viewport, media queries, fluid sizes and images that fit.
01What responsive web design means
MDN's responsive web design guide traces the term to Ethan Marcotte in 2010, who described three ingredients: fluid grids, fluid images and media queries. At the time, layouts were built with floats and percentages, and media queries did most of the work.
Today a lot of that comes for free. As the same guide puts it, modern layout methods are inherently responsive. A grid with auto-fit changes its column count on its own. A flex row with flex-wrap wraps when it runs out of room. Text in a block wraps to whatever width it is given. So a modern responsive page has three layers:
- Flexible by default. Widths in
%,fror nothing at all, never a fixedwidth: 1200pxon the page. - Fluid sizes. Type and spacing that grow smoothly with the screen, using
clamp(). - Media queries where the content breaks. A few targeted changes, not a separate design per device.
02The viewport meta tag
Before any of your CSS can respond, the browser has to know it is allowed to. Early smartphones met a web built for desktops, so they pretended to be wide. MDN's page on the viewport meta tag gives the example: a phone with a 640 pixel wide screen might lay the page out at a virtual width of 980 pixels, then shrink the result to fit. Desktop sites stay readable that way, if tiny. The catch is that a media query written for 640 pixels or less would never fire, because as far as the page knows, the screen is 980 pixels wide.
One line in the <head> turns that off:
<meta name="viewport" content="width=device-width, initial-scale=1">
width=device-width sets the layout width to the real width of the screen in CSS pixels, and initial-scale=1 starts the page unzoomed. Every responsive page needs it.
03Media queries, mobile first
A media query applies a block of CSS only when a condition is true, usually about the width of the viewport. Write the styles for small screens first, with no query at all, then add min-width queries that layer on changes as the screen gets wider:
.about { display: grid; gap: 1.5rem; }
@media (min-width: 48em) {
.about { grid-template-columns: 1fr 2fr; }
}
MDN calls this approach mobile first. It works well for two reasons. The small screen version is usually the simpler one, so it makes a good starting point, and every rule you add on top is an addition rather than an undo. Desktop first CSS tends to fill up with rules that exist only to cancel other rules.
Where to put breakpoints
A breakpoint is the width at which a media query switches on. A common habit is to copy the widths of popular phones and tablets. Do not. There are thousands of screen sizes, and next year's will be different. The MDN guide recommends breakpoints in relative units rather than the sizes of individual devices, and the practical method is simple: make your browser window narrow, widen it slowly, and add a breakpoint where the layout starts to look wrong. Lines of text that run too long, a row that feels empty, a card that gets too wide to scan.
Write breakpoints in em rather than px. An em in a media query is based on the browser's default font size, so if someone has set a larger default text size, your layout switches to the narrower arrangement sooner, which is exactly what they need.
Container queries
A media query asks about the whole viewport. Sometimes you care about the space a component has, not the screen: a card might sit in a wide main column on one page and a narrow sidebar on another. Container queries handle that. As MDN's container queries guide shows, you mark a parent with container-type: inline-size, then write @container (min-width: 30em) { ... } for its children. You will not need them for a one page site, but they are worth knowing about once you build reusable components.
04Fluid type and spacing with clamp()
Media queries change things in steps. For type and spacing you usually want a smooth change instead: a heading that is comfortable on a phone and grows steadily on bigger screens. That is what clamp() is for. It takes three values: a minimum, a preferred value and a maximum.
h1 { font-size: clamp(2rem, 1.2rem + 3vw, 4rem); }
vw is one percent of the viewport width, so the middle value grows with the screen. With the default 16 pixel root size, this heading works out at 32px on a 320 pixel phone (the preferred value would be smaller, so the minimum wins), about 49px at 1000 pixels wide, and reaches its 64px maximum at around 1490 pixels.
Drag the slider below from 320 to 1600 pixels and compare the fluid heading with a fixed one. Watch the computed size: it holds at the minimum, grows steadily, then stops at the maximum.
With clamp(2rem, 1.2rem + 3vw, 4rem) a heading grows smoothly with the viewport, but never below 2rem or above 4rem.
Two details make this accessible as well as tidy. First, keep a rem part in the preferred value, as in 1.2rem + 3vw. Text sized only in vw does not get bigger when someone zooms, because zooming changes the size of a rem but not the width of the screen. Second, MDN's clamp() reference advises that when you use it for text, the maximum should be a relative unit at least twice the minimum, so the text can still scale to 200% when the page is zoomed. Our 2rem to 4rem meets that exactly.
The same trick works for spacing. padding-block: clamp(3rem, 2rem + 4vw, 8rem) on a section gives a phone tight, sensible gaps and a wide screen room to breathe.
05Images and media that fit
An image is the easiest thing to break a responsive layout with: a 2000 pixel photo dropped into a 360 pixel screen pushes the whole page sideways. One rule, usually in the first lines of a stylesheet, prevents it:
img, video { max-width: 100%; height: auto; }
max-width: 100% lets an image shrink to fit its container but never grow past its real size, and height: auto keeps its proportions.
That fixes the layout, but a phone still downloads the 2000 pixel file. MDN's guide to responsive images explains the srcset and sizes attributes, which list several versions of the same image and tell the browser how wide it will be shown, so it can pick the smallest file that still looks sharp:
<img src="studio-800.jpg"
srcset="studio-480.jpg 480w, studio-800.jpg 800w, studio-1600.jpg 1600w"
sizes="(min-width: 48em) 50vw, 100vw"
width="1600" height="1000" alt="The studio desk by the window">
The width and height attributes do not fix the image at that size, because the CSS above still lets it shrink. They tell the browser the image's proportions before it arrives, so it can reserve the space and the text below does not jump when the image loads. We come back to that jump, and why it counts against you, in the website speed chapter.
06Making your page responsive
Your page already reflows its services grid. Now make the rest of it hold up from a small phone to a wide monitor.
h1 { font-size: clamp(2rem, 1.2rem + 3vw, 4rem); line-height: 1.1; }
section { padding-block: clamp(3rem, 2rem + 4vw, 8rem); }
p { max-width: 65ch; }
The max-width: 65ch keeps paragraphs to a comfortable line length (ch is roughly the width of one character), however wide the screen gets. Next we add the last layer of a page, JavaScript, and look at what it should and should not be trusted with in the progressive enhancement chapter.
Check your understanding
3 questions
Key takeaways
- Without the viewport meta tag, phones lay the page out as if they were a desktop screen and your media queries never fire.
- Write the small screen styles first, then add min-width media queries where the content starts to look wrong, not at device sizes.
- clamp() gives type and spacing a minimum, a fluid middle and a maximum; keep a rem part so text still grows when people zoom.
- max-width: 100% stops images breaking the layout, and srcset with sizes stops phones downloading desktop sized files.
Sources
- Responsive web designMDN Web Docs, checked
- <meta name="viewport"> HTML attribute valueMDN Web Docs, checked
- CSS container queriesMDN Web Docs, checked
- clamp() CSS functionMDN Web Docs, checked
- Using responsive images in HTMLMDN Web Docs, checked