Free breakpoint and preference query builder
Media query generator with bounds that meet exactly
Free, no signup. Give it one pixel width and it writes the breakpoint both ways — the range form (width >= 48em) that Safari 16.4 completed browser support for in March 2023, and the min-width/max-width pair with the upper bound already reduced so two bands cannot both claim 768px. Beside the width sit 14 features that have nothing to do with viewport size, each showing what the browser you are reading this in reports right now, and a list of up to eight breakpoints comes out as a stylesheet you can copy or download.
- 100% free
- No signup
- Both syntaxes
- 14 feature queries
- Up to 8 breakpoints
Press Ctrl+V anywhere on the page to drop in a breakpoint list or a whole @media rule — no need to click the field first.
This browser reports an initial font size of 16px, so 1em in a query below is 16px here — even though the root element computes to 16px. A reader who raised their default font size moves every one of these breakpoints.
34 of 4,000 characters. A missing semicolon is added for you.
Conditions that are not about width
Right column: what this browser reports now| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| not implemented | ||
| — | ||
A feature its engine has never implemented matches neither value, which is why some rows read “not implemented” rather than showing a default.
CSS
@media (width >= 48em) and (prefers-color-scheme: dark) {
.card {
padding-inline: 2rem;
gap: 1.5rem;
}
}How to write a breakpoint that does not overlap
Syntax first, then the conditions, then the whole ladder if you need more than one.
Choose the syntax and the unit before the number
The two button groups at the top decide the shape of everything below. Range syntax writes the comparison out in full and needs no fudge factor; the legacy pair writes min-width and max-width and asks how much to take off the upper bound, 0.02px as Bootstrap 5 does or a whole pixel. The unit menu converts your pixel figure using the initial font size this browser reports, which is the value a media query resolves em and rem against — not the font size the page sets on the root element.
Tick the conditions that are not about width
Fourteen keyword features sit in the table on the right, from prefers-color-scheme and prefers-reduced-motion through pointer, any-hover and orientation to display-mode and dynamic-range, plus a high-DPI row that switches between (resolution >= 2x) and (min-resolution: 2dppx) with the syntax. The right-hand column reports what this browser answers for each one, live, so a row that stays blank is telling you the engine has never implemented that feature. Type the selector and the declarations that go inside; the field holds 4,000 characters, checks that the braces balance and adds a missing semicolon.
Switch to the ladder when you need the whole set
Paste or type a comma-separated list of pixel widths — up to eight, sorted and de-duplicated for you — and pick mobile first, desktop first or exclusive bands. The table names every band, the widths it actually matches and, in legacy syntax, the sliver of width that no band covers. Copy CSS takes the stylesheet to the clipboard and Download .css saves it as breakpoints.css.
Technical specifications
| Width syntaxes | Range form with one bound or two (the two-sided comparison is emitted as a single condition), or the legacy min-width and max-width pair — the same breakpoint written both ways from one number |
|---|---|
| Non-width features | 14 keyword features carrying 36 values between them: prefers-color-scheme, prefers-reduced-motion, prefers-contrast, prefers-reduced-transparency, forced-colors, orientation, hover, any-hover, pointer, any-pointer, dynamic-range, display-mode, scripting and update, plus a high-DPI condition |
| Units | px, em and rem; em and rem are divided by the initial font size measured from this browser with font-size: medium, which is what a query resolves them against, rather than the root font size the page sets |
| Exclusive upper bound | 0.02px (Bootstrap 5's value — 0.01px is unsafe on WebKit, bug 178261) or a full 1px, applied before the unit conversion so 768px becomes 47.99875em or 47.9375em; range syntax needs neither |
| Breakpoint ladder | 1 to 8 breakpoints between 1 and 5000px, sorted ascending and de-duplicated on entry, expanded into n+1 bands under mobile-first, desktop-first or exclusive-band strategies |
| Live browser column | 37 MediaQueryList objects evaluated in your tab and re-read on every change event, so rotating a tablet or switching the system theme updates the column without a reload |
| Declaration field | 4,000 characters, brace balance checked before the rule is written, and a missing trailing semicolon added per line |
| Output | One @media block or a full ladder, copied to the clipboard or saved as media-query.css or breakpoints.css with a text/css MIME type; the readings about your device stay in the page |
Frequently asked questions
Why do (max-width: 767px) and (min-width: 768px) leave a gap?
Because a viewport can be 767.5px wide and neither rule covers it. Both prefixes are inclusive, so an integer pair either collides on the shared value or, once you step the upper one down to 767, opens a window that fractional widths drop into — browser zoom, a scrollbar eating part of a device pixel, or a display whose CSS width simply is not a whole number. Bootstrap 5 subtracts 0.02px instead of 1px for exactly this reason, and chose 0.02 over 0.01 because WebKit rounded the smaller value up (bug 178261). This page will write either subtraction and shows the width of the resulting dead zone in the band table, but the real fix is the range syntax, where the upper bound is exclusive by definition and nothing is subtracted at all.
Should breakpoints be written in px, em or rem?
em, if the layout should follow a reader who enlarged their text. Inside a media query em and rem resolve to the same thing — the browser's initial font size, the value in the user's own settings — and never to the font-size you declared on the html element, because no element style has been computed at the moment the query is evaluated. A reader running a 20px default therefore gets 48em = 960px rather than 768px, and the layout changes when their text genuinely needs the room. A page that sets html { font-size: 62.5% } shows the split most sharply: 1rem is 10px in every declaration and still about 16px in every query. The panel above prints the initial font size measured from this browser next to the root size so you can watch the two disagree.
Can I ship the range syntax today?
Yes — Firefox 102 in June 2022, Chrome and Edge 104 in August 2022 and Safari 16.4 in March 2023, so every browser released in the last three years parses it. An engine older than that treats the whole query as invalid and skips the styles inside rather than misapplying them, which is safe but not graceful. If you still support Safari 15 or an aging Android WebView, generate the legacy pair here as well and put it first, or let postcss-media-minmax rewrite the range form into min- and max- prefixes at build time.
Why does my prefers-color-scheme: dark block never fire?
Three causes, in the order worth checking. The operating system is not actually in dark mode: the query reports the system or browser setting, so an in-app theme switch has to be a class or a data attribute and cannot be a media query. The page has opted out — a meta color-scheme of light, or color-scheme: only light in CSS, pins the rendering and the query follows suit. Or the condition being tested is (prefers-color-scheme: no-preference), a value the specification kept but no shipping browser reports, which makes the block dead code. The live column in the table tells you which of light and dark this browser is answering with at this moment.
Is (pointer: coarse) a reliable way to detect a phone?
No, and it was never meant to be. pointer describes the primary input device, so a Windows laptop with a touchscreen usually reports pointer: fine while being perfectly touchable, and an iPad flips from coarse to fine the moment a trackpad is attached. Ask any-pointer: coarse whether a touch input exists at all, and pointer: coarse what the user is most likely using right now — the first decides hit-target size, the second decides layout. The same split applies to hover and any-hover, and hover: none is the query that should hide a tooltip which only appears on hover, because on a touchscreen the first tap fires :hover and the second activates the link underneath.
Does prefers-reduced-motion: reduce mean removing every animation?
No — it asks for the motion that provokes vestibular symptoms to go, not the feedback that makes an interface readable. The setting exists for large-area movement: parallax, sliding page transitions, zooming, spinning, anything that sweeps a big region of the screen. Cross-fades, color changes and short opacity transitions are the accepted substitutes. The blunt implementation, collapsing every duration to 0.01ms, is what the stylesheet behind this page does and is a fair default for a text site, but on a product interface it also removes the 150ms fade that told someone a panel had opened.
Why is my media query ignored when the selector clearly matches?
Because a media query contributes no specificity — the rule inside competes on exactly the same terms as the rule outside. Two declarations with the same selector are then settled by source order, so a base rule written after the query wins at every width and the query looks broken. Keep queries below the rules they override, order lower-bound queries from narrow to wide, and note that an !important inside a query still loses to a later !important at the same specificity. When one rule set genuinely has to beat everything else, the cascade layer it sits in is the lever, not the query.
About breakpoints, range syntax and preference queries
The oldest bug in responsive CSS is a one-pixel one. min-width and max-width are both inclusive comparisons, so a pair written as 768 and 768 applies two bands at the same width, and the usual correction — dropping the upper one to 767 — swaps the overlap for a hole. Viewports are not integers: zoom levels, scrollbars and scaled displays all produce fractional CSS widths, and 767.5px matches neither rule. Bootstrap 5 subtracts 0.02px instead of a whole pixel, having found that 0.01px was rounded up by WebKit (bug 178261), which is why the framework's compiled stylesheet is full of values like 767.98px. Media Queries Level 4 removed the need for any of it by letting the feature be compared directly, so an upper bound can be genuinely exclusive and two bands can share an edge without sharing a pixel. Generators that still emit only integer min-/max- pairs are shipping the bug; the ones that emit min-device-width are worse, since that feature describes the screen rather than the window and has been deprecated since the same specification.
The second thing worth getting right is the unit, and it has a rule that surprises even people who have written breakpoints for years: inside a media query, em and rem are identical, and both ignore your stylesheet. The query is evaluated before any element has a computed style, so the length resolves against the browser's initial font size — the setting in the reader's own preferences, 16px unless they changed it. Set html to 62.5% and 1rem becomes 10px in every declaration you write while staying roughly 16px in every query, which is how a carefully-built type scale ends up switching layouts at the wrong moment. The panel above measures that initial size from your own browser rather than assuming 16, and the px to rem converter handles the arithmetic on the declaration side, where the root size does apply. The practical consequence is that em breakpoints move with a reader who enlarged their default text and px breakpoints do not.
Two neighboring pages on this site argue that intrinsic sizing has made breakpoints largely unnecessary — the grid generator for card lists that fit their own columns, the flexbox generator for rows that wrap on their own. On the narrow claim they are right, and container queries take another slice: a component that reacts to its own box no longer needs to know the viewport at all. What does not follow is the conclusion people draw from it. Width was only ever one feature among roughly twenty, and the ones left over have no layout substitute whatsoever — nothing about a track list can tell you that someone asked their system for less motion, a coarse pointer or a high-contrast palette. That is the direction this tool leans: fewer width queries, more preference queries. It matters most where movement is involved, since prefers-reduced-motion decides whether the output of the animation generator, the easing chosen in the cubic bezier editor and the stops built in the keyframes generator should run for that visitor at all. Media queries still hold the ratio cases too, which is where an orientation condition and the aspect ratio calculator end up in the same rule.
Where the browser probing happens
Every number on this page is worked out by JavaScript running in the tab you are reading it in. Nothing you type, paste or open is uploaded, logged or kept, which is also why the tools carry on working after you disconnect from the network.
The live column is the one part of this page that reads something about your machine — its color scheme, pointer type and pixel ratio — and it does so with matchMedia inside the tab. Those answers are rendered next to the checkboxes and nowhere else: no fingerprint is assembled, nothing is stored, and closing the page ends it.