Course outline · 0% complete

0/30 lessons0%

Course overview →

Media queries and mobile-first

lesson 7-2 · ~9 min · 22/30

One page, every screen

More than half of all web traffic comes from phones, so a layout that only works at desktop width fails most visitors. There is also no separate mobile version of a stylesheet, so one file must adapt itself, and media queries are the mechanism.

A media query applies CSS only while a condition about the device is true.

.cards {
  display: grid;
  grid-template-columns: 1fr; /* phones: one column */
}

@media (min-width: 640px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .cards { grid-template-columns: repeat(3, 1fr); }
}
Screen widthColumns
below 640px1
640px and up2
1024px and up3

Read @media (min-width: 640px) as at 640px wide and up. The widths where the layout changes, here 640 and 1024, are called breakpoints.

Writing base rules for the smallest screen and layering desktop upgrades on with min-width queries is called mobile-first, and it is the standard approach. Phone layouts are the simple ones, so enhancing upward beats gutting downward.

1 column2 columns3 columnsbase rulemin-width: 640pxmin-width: 1024pxScreen width increases to the right, and later queries win because they come later in the file.
Mobile-first layering: the base rule covers every width, and each min-width query adds an override from its breakpoint upward.

The tag that makes it all work

One line in the head, part of the lesson 2-1 skeleton family, or phones will pretend to be 980px-wide desktops and shrink everything to fit.

<meta name="viewport" content="width=device-width, initial-scale=1">
PartMeaning
width=device-widthmatch the device's real width
initial-scale=1start at 100% zoom

It tells the browser to make the layout viewport match the device's real width at full zoom, and every responsive page needs it.

Skipping it means carefully written media queries never fire on phones, because the browser reports a false width. The failure is confusing precisely because the CSS is correct.

Testing without a drawer full of phones is what DevTools is for, since its device toolbar resizes the viewport freely. Lesson 9-1 covers it properly.

What base rules cover

In mobile-first CSS, the rules written outside any media query target all screens, starting from the smallest.

Base rules always apply, and min-width queries then add overrides as the screen grows.

Rule locationApplies at
outside any queryevery width
inside min-width: 640px640px and up
inside min-width: 1024px1024px and up

That layering is the whole mobile-first pattern, meaning a simple base plus targeted upgrades. Since later rules override earlier ones at equal specificity, the queries must come after the base rules in the file.

The breakpoint logic as a function

pickColumns(width) reproduces the .cards breakpoints, returning 1 below 640px, 2 from 640px, and 3 from 1024px.

function pickColumns(width) {
  if (width >= 1024) return 3;
  if (width >= 640) return 2;
  return 1;
}

console.log(pickColumns(390));
console.log(pickColumns(640));
console.log(pickColumns(800));
console.log(pickColumns(1024));

Output

1
2
2
3
WidthColumns
3901
6402
8002
10243

The largest breakpoint is checked first, then the rest fall through, which mirrors how the last matching media query wins in CSS.

min-width: 640px matches a width of exactly 640, so the comparison uses >= rather than >. Getting that boundary wrong produces a layout that is broken at exactly one width, which is the hardest kind of bug to notice.

When queries work in DevTools but not on a phone

Media queries that work in desktop DevTools while a real phone shows a shrunken desktop layout mean the viewport meta tag is missing.

<meta name="viewport" content="width=device-width, initial-scale=1">
With the tagWithout it
the phone reports its real widthit reports a pretend 980px
min-width queries firethey see 980px and never fire

It goes in the head, next to charset and title. Because the phone lays the page out at a fake 980px and then zooms out to fit, the result looks like a working desktop page rendered too small, rather than like broken CSS.