You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This "inlinification" should answer questions about cycles (etc) automatically. I wouldn't expect implementations to literally perform this, of course. It's just a way of explaining the behavior from existing primitives.
Multiple levels of @if would desugar into a compound if-test:
.box { border-radius:if(style(--mode:pill) and style(--theme:dark):10px; else:revert-rule); }
There might be a potential trap when using nesting, e.g. authors could reasonably expect the following if-test to branch off of <div class=box>'s variables, when in reality style(--mode:pill) gets evaluated against <div class=inner>'s variables:
However, this is similar to how different rules within a single @container rule can target totally different containers based on the element being matched.
Not a duplicate of @when. That just combines the existing @media and @supports queries into one. As proposed here, @if can query custom properties on the subject element itself, which requires a totally different model. EDIT: Forgot to say: if we adopt this, we may not actually need @when, though.
(The main reason to have @when is just to combine the currently disparate query constructs together; it's kinda annoying to try and query on both an MQ and an SQ at the same time. This @if idea is indeed something completely different.)
This sounds pretty good overall; it definitely saves on typing in some cases vs repeatedly inlining the same if() check, as your example shows.
However, I don't like the proposed behavior for nesting style rules inside of @if. This is not the same issue as @container. In @container, the element you're querying is always an ancestor of the element you're styling, so the rule's position "above/outside" the style rule makes intuitive sense. And if the condition you're testing isn't intercepted by anything, you can do further nested rules and they'll test against the same ancestor; it's a minor footgun to watch out for, but usually not an issue in practice I think.
In your proposed @if, that's not at all true - it's always the element itself being tested, which means that nested elements by definition evaluate the test against something different. That's super confusing, imo; testing a non-inherited custom property will virtually always cause nested rules to fail for no apparent reason.
So, I think @if here should only be allowed in a nested context, and then only allow declarations, not style rules, inside of itself. (Plus at-rules, inheriting the same context restriction, so you can stack @ifs, and even mix it with @media or whatever.)
Yup, a block @if has always been my plan when proposing if() and revert-rule — they are its building blocks to pave the way.
My original idea was that for descendants you can use regular style queries (which would alleviate @tabatkins' concern), but I don't think that can be determined at parse time. I wonder if we can have it late-resolve depending on what the nested rule is targeting.
Nested rules should definitely not be evaluating a different condition, but that just affects how we define the desugaring. E.g. we could define that it desugars the condition to a <boolean> custom property1 and then all if()s use that custom property instead of the condition verbatim.
Footnotes
And add <boolean> as type for custom properties, obvs 😁 ↩
nesting style rules inside of @if [... is] super confusing, imo
Agree.
So, I think @if here should only be allowed in a nested context, and then only allow declarations, not style rules, inside of itself.
That would be ideal.
E.g. we could define that it desugars the condition to a custom property and then all if()s use that custom property instead of the condition verbatim.
That would indeed be neat. It would be like implicitly generating a style-container-query for it.
Unfortunately nesting isn't "DOM-structural" like that, so we have no guarantee that the outer thing actually is an ancestor of the inner things. It breaks down as soon as you use e.g. sibling selectors, .box { @if(...) { & + .thing { } } }.
@scopeis structural, so your trick should work directly beneath that rule:
Yeah, the lack of auto-scoping makes any desugaring approach unworkable. (We'll have the same problem with Mixins, fwiw; @andruud and I were chatting about this off-list today.)
While declarations-only at the beginning would be ok-ish, if we were able to come up with how to handle nested rules — it would be much-much better and less confusing for authors who would for sure try nesting stuff only to find it not working.
I think it is sensible to just disallow styling anything outside the “scope” of the topmost parent selector, so & + .thing not doing anything is totally fine from an author's perspective. I imagine, the problem is more how to desugar it? Can we detect that some rules target elements outside the “parent” scope and throw them away?
.foo {
@scope (&) { } /* Scoped according to the parent rule */
}
So @if() can just implicitly do something similar. "Throwing away" rules that are outside the scope then means those rules never match per @scope's already-defined behavior. As discussed in #13113, we'll probably want to avoid adding proximity or changing specificity here, though.
Activity
otomad commentedon Oct 9, 2025
Duplicate of
@whenandruud commentedon Oct 10, 2025
Not a duplicate of
@when. That just combines the existing@mediaand@supportsqueries into one. As proposed here,@ifcan query custom properties on the subject element itself, which requires a totally different model. EDIT: Forgot to say: if we adopt this, we may not actually need@when, though.tabatkins commentedon Oct 13, 2025
(The main reason to have
@whenis just to combine the currently disparate query constructs together; it's kinda annoying to try and query on both an MQ and an SQ at the same time. This@ifidea is indeed something completely different.)This sounds pretty good overall; it definitely saves on typing in some cases vs repeatedly inlining the same
if()check, as your example shows.However, I don't like the proposed behavior for nesting style rules inside of
@if. This is not the same issue as@container. In@container, the element you're querying is always an ancestor of the element you're styling, so the rule's position "above/outside" the style rule makes intuitive sense. And if the condition you're testing isn't intercepted by anything, you can do further nested rules and they'll test against the same ancestor; it's a minor footgun to watch out for, but usually not an issue in practice I think.In your proposed
@if, that's not at all true - it's always the element itself being tested, which means that nested elements by definition evaluate the test against something different. That's super confusing, imo; testing a non-inherited custom property will virtually always cause nested rules to fail for no apparent reason.So, I think
@ifhere should only be allowed in a nested context, and then only allow declarations, not style rules, inside of itself. (Plus at-rules, inheriting the same context restriction, so you can stack@ifs, and even mix it with@mediaor whatever.)LeaVerou commentedon Oct 14, 2025
Yup, a block
@ifhas always been my plan when proposingif()andrevert-rule— they are its building blocks to pave the way.My original idea was that for descendants you can use regular style queries (which would alleviate @tabatkins' concern), but I don't think that can be determined at parse time. I wonder if we can have it late-resolve depending on what the nested rule is targeting.
Nested rules should definitely not be evaluating a different condition, but that just affects how we define the desugaring. E.g. we could define that it desugars the condition to a
<boolean>custom property1 and then allif()s use that custom property instead of the condition verbatim.Footnotes
And add
<boolean>as type for custom properties, obvs 😁 ↩andruud commentedon Oct 14, 2025
Agree.
That would be ideal.
That would indeed be neat. It would be like implicitly generating a style-container-query for it.
As an example:
Effectively means:
Unfortunately nesting isn't "DOM-structural" like that, so we have no guarantee that the outer thing actually is an ancestor of the inner things. It breaks down as soon as you use e.g. sibling selectors,
.box { @if(...) { & + .thing { } } }.@scopeis structural, so your trick should work directly beneath that rule:In any case, I would restrict
@ifto declarations-only in the first version, if possible.tabatkins commentedon Oct 14, 2025
Yeah, the lack of auto-scoping makes any desugaring approach unworkable. (We'll have the same problem with Mixins, fwiw; @andruud and I were chatting about this off-list today.)
kizu commentedon Nov 26, 2025
Saw a wish about this on Mastodon today: https://front-end.social/@matuzo/115617707314652734
While declarations-only at the beginning would be ok-ish, if we were able to come up with how to handle nested rules — it would be much-much better and less confusing for authors who would for sure try nesting stuff only to find it not working.
I think it is sensible to just disallow styling anything outside the “scope” of the topmost parent selector, so
& + .thingnot doing anything is totally fine from an author's perspective. I imagine, the problem is more how to desugar it? Can we detect that some rules target elements outside the “parent” scope and throw them away?LeaVerou commentedon Nov 26, 2025
What if
@ifwas defined to basically have similar semantics as@scope? Something likeandruud commentedon Nov 26, 2025
Yeah, we can already do:
So
@if()can just implicitly do something similar. "Throwing away" rules that are outside the scope then means those rules never match per@scope's already-defined behavior. As discussed in #13113, we'll probably want to avoid adding proximity or changing specificity here, though.romainmenke commentedon Oct 3, 2026
This proposal is also quite crucial for mixins.
It's currently annoying to have an enum argument and then have a switch or
if/elseifchain over that enum and emit totally different styles.e.g.
The
; else:revert-ruletrick might work fine, but it isn't intuitive :)