ScreenshotNeo

BlogGuides

CSS Media Queries for Responsive Design: Examples and Best Practices

Learn how to write responsive CSS media queries, choose breakpoints from your content, adapt to user preferences, and know when container queries fit better.

By the ScreenshotNeo team4 October 202611 min read

CSS media queries apply styles when conditions about the rendering environment match. For responsive layouts, start with flexible styles that work at narrow widths, then add a query where the content needs a different arrangement. Choose that breakpoint from the design, not from a named device. For a reusable component that should respond to its own available space, consider a container query instead.

This guide shows how to build responsive layouts with media queries, adapt to input capabilities and user preferences, and avoid common breakpoint and compatibility mistakes. The examples are illustrative patterns based on the linked documentation, not claims of independent testing.

1. Understand media query syntax

A media query tests a media type, such as screen or print, and optionally one or more media features, such as viewport width or color scheme. The rules inside @media apply only when the query matches.

@media screen and (width >= 80rem) {
  .container {
    margin: 1em 2em;
  }
}

Here, screen is the media type, and joins it to a feature test, and (width >= 80rem) is a range expression. The screen type is optional when the query is only testing screen-related features:

@media (width >= 80rem) {
  .container {
    margin-inline: 2rem;
  }
}

A query matches when its media type matches and all of its feature conditions are true. You can combine conditions with and, use not to negate a query, or use only as a modifier. A comma-separated list means “match any of these queries.”

/* Wide screen, or any printed page */
@media screen and (width >= 70rem), print {
  .article {
    max-width: 70rem;
  }
}

/* Apply unless the user requests reduced motion */
@media not (prefers-reduced-motion: reduce) {
  .card {
    transition: transform 180ms ease;
  }
}

Use @media print for print-specific styles, such as removing navigation or avoiding colored backgrounds. The media types all, print, and screen are useful; older types such as tv and handheld are deprecated. A stylesheet linked with a media condition that does not match may still download at lower priority, even though its rules do not apply. MDN’s guide to using media queries explains syntax and media types.

2. Build a responsive layout from the content

Use flexible layout as the foundation. Grid, flexible tracks, relative units, and sensible minimum and maximum sizes can handle many changes in width without any media query. Add a query when the content needs a conditional change, such as switching from one column to two.

This complete HTML and CSS example starts with a single column and adds columns when there is enough room. The breakpoint is an example, not a universal device threshold. Change it when your content becomes cramped or the wider arrangement becomes useful.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Responsive article cards</title>
  <style>
    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 1rem;
      font: 1rem/1.5 system-ui, sans-serif;
      color: #18212b;
      background: #f5f7fa;
    }

    .cards {
      display: grid;
      grid-template-columns: minmax(0, 1fr);
      gap: 1rem;
      max-width: 76rem;
      margin-inline: auto;
    }

    .card {
      min-width: 0;
      padding: 1.25rem;
      border: 1px solid #d5dce5;
      border-radius: 0.75rem;
      background: white;
    }

    .card h2 {
      margin-block: 0 0.5rem;
      font-size: 1.25rem;
    }

    .card p {
      margin: 0;
    }

    @media (width >= 42rem) {
      .cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }
    }

    @media (width >= 68rem) {
      .cards {
        grid-template-columns: repeat(3, minmax(0, 1fr));
      }
    }
  </style>
</head>
<body>
  <main class="cards">
    <article class="card">
      <h2>First card</h2>
      <p>A short description that can wrap naturally.</p>
    </article>
    <article class="card">
      <h2>Second card</h2>
      <p>Another description with the same basic structure.</p>
    </article>
    <article class="card">
      <h2>Third card</h2>
      <p>A third item for the wider grid.</p>
    </article>
  </main>
</body>
</html>

The viewport meta element gives mobile browsers a layout viewport corresponding to the device width. The base rule remains a usable one-column layout. The media queries progressively add columns when the available width supports them.

Choose breakpoints by checking the layout

  1. Start with a narrow layout and flexible sizing.
  2. Resize the viewport gradually, rather than checking only a few preset device widths.
  3. When text, controls, or columns become cramped, decide what structural change would improve the layout.
  4. Add a breakpoint at the width where that change makes sense.
  5. Check widths just below and above the breakpoint, plus larger and smaller widths.

Relative units such as rem are useful for breakpoints because the condition can track text sizing. Avoid treating any published breakpoint table as a rule for every site. Responsive breakpoints describe where a design change is needed, not a particular phone or tablet model. See MDN’s responsive design guide for the broader workflow.

3. Use queries for capabilities and preferences

Media queries can test more than width. Use capability and preference queries when they change how an interaction or presentation should work. They describe the environment or user preference; they do not identify an exact device model.

Orientation

@media (orientation: landscape) {
  .media-panel {
    grid-template-columns: minmax(0, 1.4fr) minmax(15rem, 1fr);
  }
}

Use orientation when the layout genuinely benefits from landscape space. Do not assume every landscape viewport is large; a short, wide viewport still needs room for its content.

Hover and pointer capability

@media (hover: hover) and (pointer: fine) {
  .card a:hover {
    text-decoration-thickness: 0.15em;
  }
}

This can add a hover enhancement when the primary input supports hover and fine pointing. It is not a guarantee that every input available to a person has those properties. Keep essential actions available without hover.

Reduced motion

.drawer {
  transition: transform 180ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .drawer {
    scroll-behavior: auto;
    transition: none;
  }
}

Use this preference to remove or reduce nonessential motion. Ensure that content and state changes remain clear without animation.

Color scheme

:root {
  color-scheme: light;
  --page: #ffffff;
  --text: #18212b;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --page: #151a21;
    --text: #f1f4f8;
  }
}

body {
  color: var(--text);
  background: var(--page);
}

Forced colors

@media (forced-colors: active) {
  .custom-control {
    border: 1px solid ButtonText;
    color: ButtonText;
    background: ButtonFace;
  }
}

Forced-colors modes alter color presentation to support accessibility needs. Check that custom controls still have visible boundaries and states; avoid relying only on subtle background colors.

Resolution and print

/* A higher-resolution output, such as a print or high-density context */
@media (min-resolution: 2dppx) {
  .fine-detail {
    /* Optional higher-resolution treatment */
  }
}

@media print {
  nav,
  .screen-only {
    display: none;
  }

  body {
    color: #000;
    background: #fff;
  }
}

Resolution queries are available when resolution affects an asset or presentation. Do not use them as a substitute for scalable images where responsive image techniques fit. Print queries can remove screen-only controls and adapt contrast for paper. The media features and categories include width, orientation, resolution, hover and pointer, forced colors, color scheme, and reduced motion. Refer to MDN’s media queries reference and media query fundamentals for feature descriptions.

4. Decide between media queries and container queries

Use a media query when a rule depends on the viewport or environment: page-level columns, navigation layout, print output, input capability, or a user preference. Consider a container query when a component should adapt to the space its containing element provides, regardless of the overall viewport.

.card-list {
  container-type: inline-size;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@container (width >= 34rem) {
  .card {
    grid-template-columns: minmax(10rem, 1fr) 2fr;
    align-items: center;
  }
}

The container establishes a queryable inline-size context; the card layout changes when that container reaches the condition. This is useful when the same component appears in both a narrow sidebar and a wide content area. Use viewport queries for decisions that belong to the page as a whole, and container queries for component behavior that belongs to its local space. See MDN’s overview of media and container query use.

5. Best practices checklist

  • Make the base layout flexible. Use grid or flex layouts, relative sizing, and min/max constraints before adding many conditions.
  • Use the smallest number of meaningful breakpoints. Add a query when it changes the layout in response to a real content need.
  • Prefer relative breakpoint units. Choose the unit and condition intentionally; do not copy a device-specific breakpoint list without checking the design.
  • Keep content usable between conditions. A layout should not work only at the exact widths you previewed.
  • Use capability and preference queries for their intended purpose. Keep essential behavior available without hover and respect reduced motion.
  • Use container queries for local component adaptation. This makes a component less dependent on where it happens to appear in the page.
  • Do not use deprecated device dimensions as responsive shortcuts. Prefer viewport features such as width; device-specific width, height, and aspect-ratio features are deprecated in Media Queries Level 4.
  • Check accessibility states. Verify contrast, visible control boundaries, keyboard focus, and behavior with reduced motion or forced colors.
  • Keep query scope understandable. Group related responsive rules and avoid overlapping conditions that make the final computed style hard to reason about.

6. Troubleshooting common problems

Symptom Likely cause Fix
The breakpoint never seems to activate. The query has a syntax error, targets a different condition than expected, or the viewport has not crossed the threshold. Check parentheses and units, inspect the actual viewport width, and temporarily use a visible style change to confirm the rule matches.
The layout overflows even though the grid is responsive. A grid child has an intrinsic minimum width, or a long word or unbreakable element cannot shrink. Use minmax(0, 1fr) for tracks, set min-width: 0 on the relevant child, and handle long content such as code or URLs.
A hover interaction is unavailable on touch input. The interface relies on hover for an essential action. Keep the action visible or provide a click/tap path; use (hover: hover) only for optional enhancement.
Dark mode changes some colors but leaves others unreadable. Only part of the color system was updated, or images, borders, and controls still assume a light background. Use shared color variables and review text, borders, form controls, focus indicators, and illustrations together.
The layout changes correctly at one width but breaks nearby. The breakpoint was chosen from a device preset rather than the content, or only a few widths were considered. Resize continuously around the transition, reduce fixed widths, and move the breakpoint to the point where the content needs the change.
A component does not adapt when moved into a narrow column. Its rules depend on viewport width even though the available component space changed. Use a container query for that local layout and ensure the component is inside a container with container-type.
Print output contains navigation or low-contrast backgrounds. No print-specific rules were added. Use @media print to hide screen-only controls and set readable print colors.

7. Performance, reliability, and testing

Media queries are conditions in CSS, so a responsive change does not require JavaScript viewport detection or separate markup for each device category. Keep the rules simple and use flexible layout as the base; this reduces the number of conditional cases you need to maintain. The available source guidance does not provide benchmark figures, so no specific performance gain is claimed here.

For reliability, test at widths just below, at, and above each breakpoint, and include intermediate widths. Also check zoomed text, keyboard navigation, print output if supported, and relevant user preferences such as reduced motion, dark scheme, and forced colors. A query describes a condition, so verify that the fallback base styles remain useful when that condition does not match.

Media queries help a page adapt; they do not by themselves guarantee that a screenshot or browser capture represents the intended state. For visual reviews, check representative viewport widths and preference states. ScreenshotNeo is a website screenshot API and MCP server for developers. Its captures can use viewport and device settings, and the API accepts many parameters used by other screenshot APIs. It is separate from CSS: the stylesheet still defines the responsive behavior.

8. Capture a responsive page with ScreenshotNeo

To inspect your responsive layout as an image, capture the page at the viewport you want to review. ScreenshotNeo can return PNG, JPEG, WebP, or PDF; it also supports device presets and custom viewports, full-page capture, and CSS or JavaScript adjustments. See the ScreenshotNeo website and API documentation for setup and options.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  --data-urlencode viewport_width=1280 \
  --data-urlencode viewport_height=900 \
  -o responsive.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://example.com",
        "viewport_width": 1280,
        "viewport_height": 900,
    },
    timeout=90,
)
r.raise_for_status()
with open("responsive.webp", "wb") as image:
    image.write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com',
  viewport_width: '1280',
  viewport_height: '900'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('responsive.webp', bytes));

Change the viewport values to capture just below and above your CSS breakpoints. The API offers many options, including full-page capture with lazy images loaded, element capture by CSS selector, dark mode, 12 device presets, retina scale, custom CSS and JavaScript, wait conditions, custom headers and cookies, caching with a chosen TTL, signed links for public image tags, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI spec. The parameter names used by other screenshot APIs also work to ease migration; see the documentation for exact parameters and response details.

9. Or skip the browser setup

One GET request can return a screenshot without setting up browser automation. Replace the example URL and API key with your page and key.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say which page verdict applied and whether it was billed. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. See the documentation for options and sign up free for 1,000 screenshots a month with no card.

10. Frequently asked questions

Do I need media queries for every responsive page?

No. Fluid grids, flexible sizing, and intrinsic layout can handle many changes without conditional rules. Add media queries when the design needs a real change in structure or presentation.

Can a media query detect a particular phone or tablet?

Media queries test features of the rendering environment, such as width, orientation, or input capability. They are not a reliable way to identify an exact device model.

Should I use width or device-width?

Use viewport width for responsive layout decisions. Device-specific width descriptors are deprecated in Media Queries Level 4 and are not the preferred basis for page breakpoints.

Can I combine media queries with container queries?

Yes. A page can use viewport conditions for its overall structure and container conditions for components that adapt to their local space.

Do nonmatching media-specific stylesheets avoid downloading?

Not necessarily. A stylesheet whose media condition does not match can still download at lower priority, although its rules do not apply unless the query matches.