Named Breakpoints Without Sass
I stopped using Sass awhile ago. CSS nesting and custom properties cover almost everything I used it for. It's been liberating to not have a build step for my CSS.*
But I do miss named breakpoints. In Sass, for example, you could set $md: 48em and use it in all your @media queries.
$md: 48em;
@media (min-width: $md) {
...
}Early on, custom properties looked like they'd be the holy grail for this! Alas…
:root {
--breakpoint-md: 48em;
}
@media (min-width: var(--breakpoint-md)) {
/* lol nope */
}I assumed this was an oversight that would get fixed eventually. Turns out, it was intentional.
The problem is that custom properties are element-scoped. They cascade and inherit like any other property, but their values aren't known until the browser computes styles for a specific element.
A media query is, well, not an element. It's evaluated against the viewport before the cascade runs, so there's no element to read --breakpoint-md from, and using :root would have been a malformed bastardization of the specification.*
The objection was scoping and evaluation order, but knowing why doesn't make it any less disappointing.
There are two proposals to help with this problem, but neither has shipped.
@custom-media from Media Queries Level 5 lets you name an entire query and reuse it.
@custom-media --tablet (width >= 48em);
@media (--tablet) {
...
}The spec has been around for years. Firefox has it behind a flag, and Chrome and Safari haven't shipped it at all. It also names a query, not a length, so you can't reuse the same number in a width property somewhere else.
Author-defined env() variables are closer to what I actually want. Unlike custom properties, environment variables are global and don't cascade, which is why they're allowed in media queries. Browsers provide a few, like safe-area-inset-top, but there's no way for authors to define their own yet. The spec is a working draft as of 2025, and how you'd even declare one is still up in the air.
I stumbled upon this post by Mastro, which pointed at Andrew Walpole's CodePen. The idea is you write the viewport sizes in @media, set a named token on :root, and access it with a style query instead of repeating the media query.
:root {
--viewport: 'desktop';
@media (max-width: 64em) {
--viewport: 'tablet';
}
@media (max-width: 37.5em) {
--viewport: 'mobile';
}
}
@container style(--viewport: 'mobile') {
/* Styles for the mobile bucket */
}
@container style(--viewport: 'desktop'),
This isn't a real viewport query, of course. It's a style query that happens to track one, and style queries for custom properties only landed in Firefox 151 back in May, so anyone on an older version won't get them. It's definitely a neat trick, though!
Unfortunately, there's no clean fallback for unsupportive browsers. @supports can't detect style queries, and even if it could, the only workaround would be to duplicate everything in @media. 😕
So it's a bit too early to use for production, but it will soon be a good reason to not keep a preprocessor around.
*Sass is one of the reasons we got -- instead of $ and I've seriously thought about making my own preprocessor because it's so awkward. But I really, really don't want a build step for my CSS.