Make a layout adapt from phone to desktop with the viewport meta tag, fluid images and min-width media queries.
Why this matters
More than half of all web traffic comes from phones, and people also browse on tablets, laptops, ultra-wide monitors and TVs. A responsive page adapts to whatever screen it lands on instead of shipping a separate mobile site. Employers expect every front-end developer to build this way by default.
You already have two responsive tools: flex-wrap and repeat(auto-fit, minmax()) adapt without any breakpoints. This lesson adds the rest: the viewport tag, fluid images and media queries.
Step 0: the viewport meta tag
Without this line, phones pretend to be about 980px wide and shrink the whole page down until it is unreadable:
<meta name="viewport" content="width=device-width, initial-scale=1">
It tells the phone to use its real width. Media queries will not behave as expected on phones without it. Do not add maximum-scale=1 or user-scalable=no: blocking zoom is an accessibility failure.
Fluid images
A 1,200px image inside a 360px phone screen overflows sideways. One rule fixes every image:
img {
max-width: 100%; /* never wider than its container */
height: auto; /* keep the aspect ratio */
}
Media queries
A media query applies CSS only when a condition is true:
@media (min-width: 48em) {
.layout {
grid-template-columns: 2fr 1fr;
}
}
min-width: 48emmeans "when the viewport is at least 48em wide". In media queries,1emis the browser's default font size, usually 16px, so 48em is 768px. Usingemmakes breakpoints respond sensibly when users enlarge their default text.- Rules inside the query are ordinary CSS rules. They follow the normal cascade, so a query placed after the base rule overrides it when it matches.
- Other useful features:
max-width,orientation: landscape,prefers-color-scheme: dark,prefers-reduced-motion: reduceandhover: hover.
Mobile-first versus desktop-first
Desktop-first writes the wide layout as the default and undoes it for small screens with max-width queries. Mobile-first writes the simplest, single-column layout as the default and adds complexity for larger screens with min-width queries:
/* Base: phones and everything else */
.layout {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
.nav-list {
display: flex;
flex-direction: column;
}
/* Tablets and up */
@media (min-width: 48em) {
.layout { grid-template-columns: 2fr 1fr; }
.nav-list { flex-direction: row; }
}
/* Large screens */
@media (min-width: 75em) {
.layout { grid-template-columns: 3fr 1fr; }
}
Why most teams prefer mobile-first:
- The base CSS is the simplest version, so the smallest, often slowest devices get the least work.
- You add rules as space allows, rather than writing a layout and then overriding it.
- It forces you to decide what really matters on the page, because the phone layout has room for only the essentials.
Choosing breakpoints
Do not pick breakpoints from a list of popular phone sizes; devices change every year. Instead, start narrow, widen the browser slowly, and add a breakpoint where your content starts to look wrong: lines grow too long, a sidebar has room to appear, the nav fits on one row. Most small sites need only one or two breakpoints.
Worked example: testing responsiveness
- Open developer tools and turn on device mode (the phone-and-tablet icon, or Ctrl+Shift+M / Cmd+Shift+M).
- Choose a phone size such as 375px wide, then drag the width handle slowly up to 1,400px.
- Watch the layout switch at your breakpoint. In Chrome, the Media queries bar above the page shows each breakpoint; click one to jump to that width.
- Also test zoom: press Ctrl/Cmd and + to 200%. With
embreakpoints, the layout should switch to the phone version, which is exactly what a low-vision user needs. - Finally, open the page on a real phone. Emulators are good, but touch targets and real fonts can surprise you.
Common mistakes
- Forgetting the viewport meta tag, so phones show a tiny desktop page.
- Mixing min-width and max-width queries for the same components, which creates gaps and overlaps at the boundaries.
- Putting the base rule after the media query, so the base silently overrides the query.
- Fixed widths such as
width: 960pxon containers; usemax-width. - Hiding important content on mobile instead of rearranging it.
Quick recap
- Add
<meta name="viewport" content="width=device-width, initial-scale=1">to every page. img { max-width: 100%; height: auto; }makes images fluid.- Mobile-first: single-column base styles, then
@media (min-width: ...)adds layout as space grows. - Pick breakpoints from your content, in
em; test with device mode and zoom.
Try it
Open the Do tab and convert a desktop-first recipe page to mobile-first.