Code of the Day
IntermediateResponsive Design

Media Queries

Media queries let you apply CSS conditionally based on viewport width, screen resolution, or user preferences — the foundation of responsive layouts.

Web FoundationsIntermediate8 min read
Recommended first
By the end of this lesson you will be able to:
  • Write a valid media query using min-width and max-width
  • Explain why content should drive breakpoint choice, not device names
  • Combine multiple conditions in a single media query
  • Use prefers-color-scheme and prefers-reduced-motion to respect user preferences

Once the viewport meta tag is in place, the browser faithfully reports the real screen width to CSS. A is how you act on that information — applying a block of styles only when a condition is true.

Basic syntax

A media query wraps a block of CSS rules in a conditional:

@media (min-width: 768px) {
  .container {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

The rules inside apply only when the viewport is at least 768px wide. Below that width the browser ignores the entire block.

The @media at-rule can test many things — width, height, orientation, resolution — but min-width and max-width are the ones you will use most.

min-width vs max-width

These two feel similar but encode opposite mental models.

min-width — "start here and add." The base styles apply everywhere; the media query adds styles for wider viewports. This is the mobile-first approach.

/* Base: one column, always */
.cards {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Wider than 640px: switch to a row */
@media (min-width: 640px) {
  .cards {
    flex-direction: row;
  }
}

max-width — "start here and subtract." The base styles are for wide screens; the query strips things back for narrow viewports. This is the desktop-first approach.

/* Base: side-by-side columns */
.cards {
  display: flex;
  flex-direction: row;
}

/* Narrower than 640px: stack vertically */
@media (max-width: 639px) {
  .cards {
    flex-direction: column;
  }
}

Both achieve the same result, but the min-width approach tends to produce leaner CSS because mobile layouts are usually simpler. You will revisit this trade-off in depth in the next lesson.

Notice that the max-width example uses 639px while the min-width example uses 640px. The one-pixel gap prevents both rules firing simultaneously at exactly 640px — a small but deliberate detail.

Choosing breakpoints

There is no canonical list of correct . Common values you will encounter are 480px, 640px, 768px, 1024px, and 1280px, but these were not handed down from the cloud — they were derived from popular device widths at a particular moment in time.

Device widths change every year. A better strategy: add a breakpoint where the content starts to look wrong, not because a device happens to have that width. Resize the browser slowly and watch when the text line-length becomes uncomfortably long, or when whitespace starts looking excessive. That is your breakpoint.

Combining conditions

A media query can require multiple conditions to be true at once:

/* Apply only between 600px and 900px wide */
@media (min-width: 600px) and (max-width: 900px) {
  .sidebar {
    width: 250px;
  }
}

/* Apply when the device is held in portrait orientation */
@media (orientation: portrait) {
  .map {
    height: 40vh;
  }
}

The and keyword requires both conditions. You can also separate queries with a comma, which acts as or:

/* Landscape phone OR wide tablet */
@media (min-width: 480px) and (orientation: landscape),
       (min-width: 768px) {
  .nav {
    flex-direction: row;
  }
}

Beyond width: user preference queries

Media queries are not only about screen size. Two queries that every site should consider:

prefers-color-scheme

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a2e;
    --text: #e0e0e0;
  }
}

When a user has enabled dark mode in their OS settings, this query fires and you can swap your colour tokens. The browser handles the detection — no JavaScript, no cookies.

prefers-reduced-motion

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Some users — those with vestibular disorders, motion sickness, or epilepsy — enable "reduce motion" in their OS accessibility settings. This query catches that preference and disables animations site-wide. It is a one-liner that has a real impact on accessibility.

Omitting prefers-reduced-motion support is an accessibility failure for some users, not just a missing feature. Add it whenever your design includes significant motion — parallax scrolling, entrance animations, carousels.

Where to write your media queries

Old pattern: collect all media queries at the bottom of the stylesheet, one large block per breakpoint. This keeps them easy to find but separates a rule from its context — you have to scroll to see the full picture for any selector.

Modern pattern: nest the media query directly inside the selector it modifies. Modern CSS (and all major preprocessors) support this:

.nav {
  display: flex;
  flex-direction: column;

  @media (min-width: 768px) {
    flex-direction: row;
  }
}

The nested form keeps each selector's behaviour self-contained and is easier to read when scanning a component's styles.

Where to go next

You understand how to write media queries. Next: Mobile-First Design — the discipline of writing base styles for the smallest screen and layering complexity upward, and why the discipline produces leaner, more maintainable CSS.

Finished reading? Mark it complete to track your progress.

On this page