Media Queries and Breakpoints

A media query applies CSS only when a condition is true, such as a screen at least 40rem wide, a dark theme or a mouse that can hover, and breakpoints go where your content needs them.

Journeyman · CSS · Web Development · Updated

After this lesson you can

  • Write a media query with min-width or the range form and say which screen widths it applies to
  • Choose the media feature a job needs, such as width, orientation, hover or a prefers- setting
  • Place a breakpoint where the content breaks, not at the width of a device

Key takeaways

  • A media query wraps rules that apply only when its condition is true, such as @media (min-width: 40rem).
  • min-width means "at least this wide" and max-width means "at most this wide". The range form (width >= 40rem) says the same thing.
  • Media features test more than width, such as orientation, hover, and prefers-color-scheme or prefers-reduced-motion.
  • Put a breakpoint where your content starts to look wrong, not at the width of a particular phone or tablet.
  • Write breakpoints in rem, so the layout follows the reader's own text size.

Sol Taco Truck's menu is a single column, which is perfect on a phone. On a laptop, it's a long, thin strip down a wide, empty screen, and the owner asks: "Can the menu go side by side when there's room?" You need a way to say "only when the screen is this wide, do this". You'll write that sentence on almost every site you build, and in nearly every front-end interview someone asks how you'd make a layout change at a certain size.

If it's this wide, then...

A coffee shop puts out its patio tables only when it's warm enough: "if it's at least 65 degrees, open the patio". The shop is the same; one rule switches on when the condition is true.

A media query is that "if" for CSS. It holds rules that apply only while its condition is true:

@media (min-width: 40rem) {
  .menu {
    grid-template-columns: 1fr 1fr;
  }
}

The @ is read "at", so @media is read "at media". Rules that start with @ are called at-rules: you met one already, @font-face. This one reads "at media, min width 40 rem": on a screen at least 40rem wide, give the menu two columns. On a narrower screen, the browser skips everything inside the curly braces. (grid-template-columns: 1fr 1fr is two equal columns, from CSS Grid: Rows and Columns.)

The rules inside are ordinary rules, with their own braces. Count them as you type: one pair for the media query, one pair for each rule inside it.

min-width and max-width

The condition in the parentheses is called a media feature. The two you'll use most are about the width of the viewport:

  • min-width: 40rem is "at least 40rem wide": 40rem and wider.
  • max-width: 40rem is "at most 40rem wide": 40rem and narrower.

Two conditions can be joined with and, so both must be true:

@media (min-width: 40rem) and (max-width: 63.99rem) {
  .hours {
    font-size: 1.25rem;
  }
}

That reads "at least 40rem and at most 63.99rem": tablets and small laptops, but not wide screens.

Why rem? With the usual browser setting, 1rem is 16 pixels, so 40rem is 640 pixels. A reader who sets their text to Large (20 pixels) gets bigger text, and 40rem becomes 800 pixels: the menu stays in one column a little longer, until there's room for two columns of their bigger text. That's exactly right. A breakpoint in pixels can't do that. To turn pixels into rem, divide by 16: 640 ÷ 16 = 40.

The range form: width >= 40rem

Newer CSS lets you write the same conditions the way a math class would:

@media (width >= 40rem) {
  .menu {
    grid-template-columns: 1fr 1fr;
  }
}

@media (40rem <= width < 64rem) {
  .hours {
    font-size: 1.25rem;
  }
}

>= is read "greater than or equal to", so the first query is "width greater than or equal to 40 rem", exactly the same as min-width: 40rem. The second is read "width from 40 rem up to, but not including, 64 rem": <= is "less than or equal to", and < is "less than". It says in one line what took two conditions joined with and before, with no 63.99 needed.

This range form works in every current browser (since 2023). You'll see both forms in real code; min-width is still the most common, so this course uses it most, and the range form where it reads better.

Try it. In any page with a heading, add @media (min-width: 40rem) { h1 { color: seagreen; } }. Open device mode and drag the width slowly from 320 pixels upward. The heading changes color at 640 pixels. Then rewrite the query in the range form and check that it changes at the same place.

More than width: other media features

Width is the feature you'll use most, but a media query can ask about other things too:

Media feature What it asks You'd use it to
(orientation: landscape) Is the screen wider than it is tall? Put the photo beside the hours when a phone is turned sideways
(hover: hover) Can the main pointer hover, as a mouse can? Show a "tap or click" hint as a hover effect only where hovering works
(prefers-color-scheme: dark) Did the reader choose a dark theme in their system settings? Give the page dark colors for people who asked for them
(prefers-reduced-motion: reduce) Did the reader ask for less animation? Turn off a sliding banner for people who get dizzy from motion

A check for orientation is called an orientation query. The prefers- features are about the person, not the screen: they come from settings people choose, so respecting them is part of making a page that works for everyone. Module 5 does much more with dark themes and motion.

@media (prefers-color-scheme: dark) {
  body {
    background-color: #1f1a17;
    color: #fff4e0;
  }
}

A media query can also name a media type. @media print { nav { display: none; } } hides the navigation when someone prints the catering menu, so the paper shows only what matters.

Breakpoints go where the content breaks

A width where the layout changes is called a breakpoint: 40rem is the taco truck's first one. A common mistake is to choose breakpoints from a list of devices: 390 for one phone, 820 for one tablet. New devices come out every year, and their sizes fall everywhere in between.

Let the content decide instead:

  1. Open the page in device mode at 320 pixels wide.
  2. Drag the width slowly wider.
  3. Stop when something looks wrong: lines of text so long they're hard to follow, cards stretched wide with empty space, a photo too big for its column.
  4. That width is a breakpoint. Turn it into rem (pixels ÷ 16) and write the media query there.
  5. Keep dragging, and repeat.

For the taco truck, the menu looked stretched at about 640 pixels, so its breakpoint is 40rem. The top of the page looked empty beside a huge photo at about 1024 pixels, so the second breakpoint is 64rem. Most pages need two or three breakpoints, not ten.

Device mode with the taco truck menu at 640 pixels wide: one column of menu cards stretched across the screen, each card's short lines lost in empty space, the point where a second column fits

Check yourself

2 questions to try on the lesson page.

So what

A media query is an "if" for your CSS: if the screen is wide enough, if the reader prefers dark, if they can hover. Put your breakpoints where your content asks for them, in rem, and the layout will fit screens that haven't been made yet.

Key terms

Cheat sheets

Related