CSS Media Queries — Practical Examples for Every Breakpoint
Quick answer
💡A CSS media query applies styles conditionally based on viewport width, orientation, or user preference. Wrap rules in @media (max-width: 768px) { } for desktop-first or @media (min-width: 768px) { } for mobile-first. The viewport meta tag is required on every page for queries to fire correctly on mobile devices.
Error symptoms
- ✕
Breakpoint styles never apply on a real phone - ✕
Desktop styles override mobile rules unexpectedly - ✕
Responsive layout breaks between 768px and 1024px - ✕
Media query works in DevTools but not on device - ✕
min-width and max-width ranges overlap and conflict - ✕
Print styles bleed into screen rendering
Common causes
- •Missing viewport meta tag causes mobile browsers to zoom out and skip intended breakpoints
- •Wrong direction: using min-width when max-width is needed, or vice versa
- •CSS variables used inside media feature values — browsers silently ignore them
- •A higher-specificity rule outside the media query overrides the responsive rule
- •Unitless breakpoint values like max-width: 768 — browsers ignore unitless lengths
- •Browser cache serving stale CSS — old breakpoints still active
When it happens
- •First time setting up a responsive layout without a mobile-first baseline
- •Migrating a desktop-only site to responsive design
- •Adding a new breakpoint to an existing stylesheet with high-specificity rules
- •Testing on a physical device after only checking DevTools responsive mode
- •Using a CSS framework that has its own breakpoint system alongside custom queries
Examples and fixes
Start with stacked mobile layout, promote to horizontal on wider screens.
Mobile-first navigation collapse
❌ Wrong
/* Desktop-first — overrides required for every mobile size */
.nav {
display: flex;
flex-direction: row;
gap: 24px;
}
@media (max-width: 768px) {
.nav {
flex-direction: column;
gap: 8px;
}
}✅ Fixed
/* Mobile-first — start small, add layout for wider screens */
.nav {
display: flex;
flex-direction: column;
gap: 8px;
}
@media (min-width: 768px) {
.nav {
flex-direction: row;
gap: 24px;
}
}Mobile-first keeps the base styles minimal and layers complexity upward. The column layout is the default; the row layout is an enhancement for larger screens. This pattern means fewer overrides overall and produces cleaner CSS as breakpoints multiply. Desktop-first requires you to undo styles at every smaller breakpoint, which leads to specificity conflicts and harder maintenance. For new projects, always start mobile-first unless the design is explicitly desktop-only.
Provide a single-column base before upgrading to multi-column on tablet.
Responsive grid with base style
❌ Wrong
/* No base style — single column only exists inside media query */
@media (min-width: 480px) {
.cards { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.cards { grid-template-columns: repeat(3, 1fr); }
}✅ Fixed
/* Base single-column for all sizes, then promote */
.cards {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
@media (min-width: 480px) {
.cards { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.cards { grid-template-columns: repeat(3, 1fr); }
}Without a base style, the card container has no display or column definition on screens narrower than 480px. The grid simply does not exist at that viewport width, leaving items in normal block flow without the intended gap. Adding display: grid and grid-template-columns: 1fr as base styles ensures a deliberate single-column layout for small phones. Each media query then upgrades the column count progressively. Always define the base layout outside any media query, then layer breakpoints on top.
Respect operating system settings with prefers-color-scheme and prefers-reduced-motion.
User preference: dark mode and reduced motion
❌ Wrong
/* Ignoring user preferences entirely */
.card {
background: #ffffff;
color: #111111;
transition: transform 0.4s ease;
}
.card:hover { transform: scale(1.05); }✅ Fixed
.card {
background: #ffffff;
color: #111111;
transition: transform 0.4s ease;
}
.card:hover { transform: scale(1.05); }
@media (prefers-color-scheme: dark) {
.card { background: #1e1e1e; color: #f0f0f0; }
}
@media (prefers-reduced-motion: reduce) {
.card { transition: none; }
.card:hover { transform: none; }
}prefers-color-scheme: dark matches when the user has enabled dark mode at the OS level, allowing CSS to swap colour tokens without JavaScript. prefers-reduced-motion: reduce matches users who have enabled the reduce-motion accessibility setting — common for users with vestibular disorders or motion sensitivity. Disabling or removing transitions in this media query prevents triggering discomfort. Both queries are standard Level 5 media features supported in all modern browsers. Adding them is low effort and high impact for accessibility.
How media queries work under the hood
A CSS media query is a conditional block that tells the browser: apply these rules only when the document's rendering environment matches this description. The browser evaluates media queries after it has already parsed the HTML, built the DOM, and begun constructing the CSSOM. If the condition is true, the rules inside take effect as if they had been written at the same position in the stylesheet without a wrapper.
The media type is the first part of the query — screen, print, or the catch-all all. Most responsive work targets screen, though print is valuable for hiding navigation bars, shrinking fonts, and forcing black-on-white colours when users print pages. Omitting the type defaults to all.
Media features are the real workhorse: width, height, orientation, resolution, hover, pointer, prefers-color-scheme, prefers-reduced-motion, and more. Width features are the most common. max-width: 768px is true when the viewport is 768 pixels wide or narrower. min-width: 768px is true when the viewport is 768 pixels or wider. Both conditions are inclusive at exactly 768px, which is why the min/max boundary value must be the same to avoid a gap or overlap.
Logical operators let you combine conditions. and requires both sides to be true: @media screen and (min-width: 768px). A comma acts as OR: @media (max-width: 480px), (orientation: landscape). The not operator negates the entire query, and only is used to hide queries from old browsers that do not understand media features.
The modern range syntax is cleaner: @media (480px <= width <= 768px) targets tablets only, without overlap or gap. It is supported in all major browsers as of 2023 and reads more like programming logic than the older min/max pattern.
Diagnosing breakpoints with DevTools
Open Chrome DevTools (F12), click the Toggle Device Toolbar button (Ctrl+Shift+M on Windows, Cmd+Shift+M on Mac), and drag the viewport width handle. Watch the page reflow at each breakpoint. If the layout does not change where you expect, a breakpoint is either missing, overridden, or the viewport meta tag is absent.
In the Elements panel, select the element that should be affected and open the Styles tab. Scroll until you find the media query block. If the block is greyed out, the condition is currently false — meaning the simulated width is outside the query range. If the block is active but the property is struck through, a higher-specificity rule elsewhere is overriding it. Hover over the struck-through rule to see the winning declaration and its source file.
The Computed tab shows the final resolved value for each property. It also lists all applicable rules sorted by specificity with crossed-out losers. This is the fastest way to identify which rule won and which rule you thought should win.
For user preference queries like prefers-color-scheme and prefers-reduced-motion, use the Rendering panel. Open DevTools, press Escape to open the drawer, click the three-dot menu, choose Rendering, and scroll down to the Emulate CSS media features section. You can toggle dark mode and reduced motion without changing your OS settings.
On physical devices, enable remote debugging: connect via USB, open chrome://inspect in desktop Chrome, and inspect the device browser. This gives you the full DevTools panel against a real viewport, including the accurate meta-viewport behavior that simulators sometimes get wrong.
Common breakpoint patterns that work
The most widely used breakpoints follow content needs rather than specific device dimensions, but common starting values are 480px for small phones, 768px for tablets, 1024px for laptops, and 1280px for wide desktops. These values should be adjusted whenever your content naturally breaks — not to match a particular device.
For mobile-first projects, write all base styles outside any media query, then add min-width queries for each step up. For desktop-first, write desktop styles as the base and use max-width queries to adapt downward. The important rule is to pick one approach per project and stick to it — mixing directions creates confusing overrides.
To avoid overlap at exact pixel values, use 0.02px offset in max-width queries when mixing with min-width queries: max-width: 767.98px ensures the range ends just below 768px. Modern range syntax handles this elegantly: @media (width < 768px) is exclusive at 768px, while @media (width >= 768px) is inclusive, matching cleanly.
Container queries are the next evolution: @container (min-width: 400px) queries the element's own containing block width rather than the viewport. This is ideal for reusable components that may appear in different layout contexts — a card in a sidebar at 300px wide and the same card in a main column at 600px. Container queries require setting container-type: inline-size on the parent element.
For print media, use @media print to hide navigation, sidebars, and CTAs. Add page-break-avoid on key content blocks to prevent awkward page splits. These rules are frequently overlooked but have high value for content-heavy pages.
Mobile device gotchas and edge cases
The single most common reason media queries do not trigger on real phones is the missing viewport meta tag. Without it, mobile browsers apply a default layout viewport — typically 980px — and zoom the page out to fit the screen. At 980px simulated width, your max-width: 768px rule is never true. The fix is one line in the HTML head: meta name viewport content width=device-width, initial-scale=1.
Foldable devices and tablets that can be used in portrait or landscape orientation require careful breakpoint design. A tablet at 768px portrait becomes 1024px landscape. If your 768px breakpoint triggers the mobile layout, the device switches layouts on rotation. Consider whether orientation-specific queries or wider mobile breakpoints make sense for your content.
CSS custom properties cannot be used inside media feature values. @media (max-width: var(--bp-tablet)) is invalid and the entire media query is silently ignored. The browser does not log a warning. Extract breakpoint values into build-time variables using a preprocessor or use JavaScript to read computed properties and apply breakpoint logic there.
High-DPI screens — Apple Retina, Android xxhdpi — have a device pixel ratio of 2 or 3. A 390px iPhone screen at 3x has 1170 physical pixels, but CSS operates in logical pixels. Width in CSS refers to the logical pixel width (390px), not the physical pixel count. The resolution media feature targets physical density: @media (min-resolution: 2dppx) for Retina-class screens.
Some older Android browsers and embedded WebViews do not support modern media features like prefers-color-scheme. Always provide a sensible default outside the media query and treat user preference queries as progressive enhancement.
Mistakes developers make with breakpoints
The most common mistake is writing breakpoints for specific device models: 375px for iPhone 12, 390px for iPhone 14, 412px for Pixel. Device widths change every year and this approach becomes outdated fast. Instead, resize the viewport slowly and add a breakpoint wherever the layout visually breaks. This produces content-driven breakpoints that remain valid regardless of new device releases.
Using unitless values in media features is a silent failure. max-width: 768 has no unit and the browser ignores the entire rule without any error. Always include px, em, or rem. Note that em-based breakpoints scale with the browser's base font size — if the user has set 20px as their base, a 48em breakpoint triggers at 960px instead of 768px. Pixel-based breakpoints are more predictable.
Overlapping or gapped breakpoints create viewport ranges where no rule applies or two rules conflict. If you use max-width: 768px for mobile and min-width: 768px for tablet, the styles stack at exactly 768px — both apply simultaneously. Use max-width: 767px or the range syntax to create clean boundaries.
Putting media queries in separate files and loading them with link rel=stylesheet media= attribute is valid but can cause render-blocking. Modern best practice is to keep all media queries in the main stylesheet and rely on minification and compression rather than conditional loading.
Forgetting to test at 1px above and below each breakpoint is another frequent oversight. A bug at 769px or 767px indicates a boundary definition error. DevTools lets you type exact widths into the viewport dimension input for precise boundary testing.
Best practices for production responsive CSS
Define breakpoints as named tokens in a single location — a SCSS variable file, CSS custom properties at :root, or a design token system. Reference the same value everywhere instead of repeating 768px in dozens of places. This makes global breakpoint changes a one-line update.
Always include the viewport meta tag in your HTML template before any CSS. Teams frequently add it to component files but miss it in template files, causing production pages without it. A linting rule or template test that checks for its presence prevents this recurring issue.
Test responsive layouts with actual content, not lorem ipsum placeholder text. Long headings, names in non-Latin scripts, and verbose error messages frequently break layouts that look fine with short placeholder text. Stress-test each breakpoint with realistic data.
Order media queries consistently. Mobile-first projects should have base styles first, then min-width queries in ascending order. Desktop-first should have base styles first, then max-width queries in descending order. Consistent ordering makes it easier to read the progression of layout changes and reduces the chance of unintended overrides from source order.
Use the CSS Formatter tool to audit your responsive rules. Paste your stylesheet and review whether media queries are consistent, whether breakpoints are duplicated, and whether shorthand properties are expanded correctly. Formatting also makes it easier to spot unitless values and other silent errors before shipping to production.
For larger teams, automate breakpoint consistency by storing breakpoint values as CSS custom properties at :root and running PostCSS to convert those properties into the literal pixel values that media conditions require at build time. This keeps a single source of truth for every breakpoint threshold while ensuring the compiled output is valid CSS that the browser can evaluate without relying on runtime custom property resolution.
Responsive CSS checklist
- ✓Add viewport meta tag to every HTML page: width=device-width, initial-scale=1
- ✓Choose mobile-first (min-width) or desktop-first (max-width) and be consistent
- ✓Define breakpoints where the layout breaks, not at specific device widths
- ✓Use px or em units in media features — never unitless values
- ✓Avoid CSS variables inside media conditions — use build-time tokens instead
- ✓Check specificity of rules that should be overridden inside media queries
- ✓Test each breakpoint at exactly the boundary value and 1px above and below
- ✓Add prefers-reduced-motion and prefers-color-scheme queries for accessibility
Related guides
Frequently asked questions
What is the correct syntax for a CSS media query?
The correct syntax is @media followed by the type and feature in parentheses: @media screen and (max-width: 768px) { }. Parentheses around the feature are required. Omitting them causes the browser to ignore the entire block silently. The modern range syntax @media (width <= 768px) also works in all current browsers and is slightly more readable.
Should I use min-width or max-width for responsive design?
Use min-width for mobile-first design — base styles cover small screens and min-width queries layer on larger ones. Use max-width for desktop-first design — base styles cover desktops and max-width queries adapt downward. Most modern projects prefer mobile-first because it results in fewer overrides and aligns with performance goals of serving minimal CSS to small screens.
Why does my media query work in DevTools but not on my phone?
The most common cause is a missing viewport meta tag. Add meta name=viewport content=width=device-width, initial-scale=1 to your HTML head. Without it, mobile browsers simulate a ~980px viewport width and your breakpoints designed for 768px or smaller never trigger. Verify the tag is present in the final rendered HTML, not just a component template.
Can I use CSS variables inside media queries?
No. CSS custom properties like var(--breakpoint) are not allowed inside media feature values. The browser silently discards any query that uses them. Store breakpoints in SCSS variables or PostCSS config and output them as literal pixel values. CSS custom properties can be used inside the block of a media query, just not in the condition itself.
What breakpoints should I use for responsive design?
Common starting points are 480px for small phones, 768px for tablets, 1024px for laptops, and 1280px for wide desktops. These are guidelines, not rules. The best breakpoints are wherever your specific content breaks when you resize the browser. Add a breakpoint when the layout looks wrong, not because a device spec says to.
What is a container query and when should I use it?
A container query uses @container (min-width: 400px) and checks the width of the element's containing block rather than the viewport. Use it for reusable UI components — cards, sidebars, widgets — that may appear in different layout contexts. Set container-type: inline-size on the parent. Container queries are supported in all major browsers since 2023.
How does prefers-reduced-motion work as a media query?
prefers-reduced-motion: reduce matches when the user has enabled the reduce-motion or limit-animations setting in their operating system. Inside this query, remove or minimize transitions, animations, and parallax effects. This is an accessibility requirement for users with vestibular disorders. Testing requires toggling the OS setting or using DevTools Rendering panel to emulate it.
Does @media print affect screen rendering?
No. @media print rules apply only when the browser generates a print layout — triggered by Ctrl+P or programmatic window.print(). They do not affect screen rendering. Use print queries to hide navigation, footers, and CTAs, and to ensure body text is black on white. You can preview print styles in Chrome DevTools by selecting print in the media type emulation dropdown.
What is the difference between device-width and width in media queries?
width refers to the viewport width — the CSS logical pixel width of the browser window. device-width referred to the physical screen resolution, which has been deprecated and removed from the specification. Always use width. On high-DPI devices, CSS operates in logical pixels, so a 390px phone is 390px wide in CSS even if its screen has 1170 physical pixels at 3x pixel ratio.
All tools run in your browser. Your data never leaves your device. Last updated: 2026-05-06.