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
{{ message }}
Repository navigation
[css-cascade][css-syntax] Global revert-rule keyword that works like revert-layer but for the current rule only #10443
Edit: The original proposal was for a "!revertable flag to mark a declaration as 'can be reverted when IACVT". Iterating on this produced a resolution for a revert-rulekeyword that can be used to revert any value from the current rule, accomplishing the same goal with a more robust design, so the title has been changed to reflect that.
This came out of #5319 but I figured I should make a new post for this for visibility, since it’s a distinct proposal. #5319 discusses a keyword like revert-declaration, however I don’t think a keyword will work, since anything that is part of the value cannot be known in advance (it can be part of a variable for example).
The problem is that UAs throw the other declarations away when they see a new one in the same scope. It's impossible to know whether the new one will ever use that keyword so they can keep the old ones around too. It works with revert and revert-layer because the other declarations are kept around anyway since they’re in a separate origin/layer.
However, I think a new !-flag may actually work. TBB, but some potential names could be !revertable, !revocable, !transient, !layered. Since !-flags need to be present at parse time and are always at the end, it doesn’t have the issues that a keyword would.
When a declaration with this flag is encountered, the UA keeps old declarations around instead of replacing them with this.
/* Will not reset border-radius to 0 if --pill-radius is not set, it will just cascade normally */border-radius:var(--pill-radius) !revertable;
There can be more than one:
*{/* Will not override animation if --effect is not set to one of these values */animation:if(style(--effect: grow),1s grow) !revertable;animation:if(style(--effect: pulse),4s pulse infinite) !revertable;}
One open question is how would this work in the CSS OM. But we could just expose the last declaration, and authors can use Typed OM to get all of them (which allows append).
Reacted by Roman Komarov, Raura, Benoît Rouleau, ExE Boss, Jane Ori and Rasmus Porsager
The problem is that UAs throw the other declarations away when they see a new one in the same scope.
Ideally, we'd just not do that, and make it always possible to revert to the previous "winner" of the cascade (using a keyword). We'd need to investigate the performance implications of this, though.
Assuming an horizontal writing mode, should this revert to 2px or 1px? I guess 2px like revert-layer would do in different layers, but it seems extra annoying for CSSOM.
I wonder if it would make more sense to add an entirely new rule like
Assuming an horizontal writing mode, should this revert to 2px or 1px? I guess 2px like revert-layer would do in different layers, but it seems extra annoying for CSSOM.
This seems orthogonal to the issue we’re discussing? It would revert to whatever this would revert to:
#foo{height:1px;block-size:2px;height: invalid;}
Not sure how UAs handle the aliasing, but that doesn't seem particularly difficult to define. They'd probably keep both around?
I wonder if it would make more sense to add an entirely new rule like
I would be strongly opposed to doing this as a rule. Rules are far more heavyweight, scoping has to be defined from scratch, and authors cannot port knowledge about it from other parts of CSS. @-rules should be a last resort, not the first thing we reach for because defining syntax with good ergonomics is hard.
This seems orthogonal to the issue we’re discussing?
It isn't orthogonal. If we are only reverting to the same property, we could just shift down all declarations for the same property to the last one, then store the values together as a list, say that getPropertyValue provides the last one, and add getPropertyValues to get all of them. Similar for the setter and the priority. But we can at least keep the same indexing as now.
However, if we can revert to other properties, we can't keep assuming that a given property can only appear at most at one index. So it seems the API and the data structures used by browsers will need considerably bigger changes.
I would be strongly opposed to doing this as a rule.
Well, I would be strongly opposed to not exposing the necessary information via CSSOM.
And it doesn't seem great to pollute CSSStyleDeclaration with several things that aren't needed by normal style rules.
Most aliases are known in advance. The only complication with the issue you're pointing out is that the aliasing can be dynamic. These cases are sufficiently few they can just be stored in a data structure (if they aren’t already).
Nothing is polluting CSSStyleDeclaration, please read the first post more carefully?
But as a general principle, the ergonomics of the language itself are more important than CSS OM ergonomics. That doesn't mean the CSS OM doesn't matter, but the weightings of tradeoffs are different.
Even if an at-rule and a !-flag are both present after parse time, I think an at-rule would prompt users to put all their styles inside the block, instead of narrowing down which properties they want to enforce the revertable behavior.
Besides, as specified on the original issue at #5319, the fallback property may be on another CSS rule (or even on third-party styles), like the following:
<pclass="lorem">Lorem ipsum dolor</p>
p {
background-color: red; // declaration gets thrown away
}
.lorem {
background-color:var(--not-a-color); // declaration is IACVT
}
If the rule with the IACVT is more specific, the declaration on the lesser specific rule gets thrown away. If I understand your approach correctly, both declarations would need to be in the at-rule, which is harder if they are in different rules.
I think putting a !-flag (or even the initial proposal for a keyword) after the custom property that may be IACVT is cleaner and gives the user the necessary control.
If I understand your approach correctly, both declarations would need to be in the at-rule
@Monknow No. When the second winner of the cascade is in another rule, then it's no different than !revertable. It's not thrown away at parse time, it's just a matter of discussion whether browsers can afford to keep it during the cascade or not.
The problem with normal rules is that duplicate declarations for the same properties get overridden at parse time. So we need a different data structure. Then a different kind of rule may be cleaner.
Nothing is polluting CSSStyleDeclaration, please read the first post more carefully?
@LeaVerou Please read my comment more carefully: "I would be strongly opposed to not exposing the necessary information via CSSOM", which clashes with your proposal in the first post of not exposing it via CSSOM.
Nothing is polluting CSSStyleDeclaration, please read the first post more carefully?
@LeaVerou Please read my comment more carefully: "I would be strongly opposed to not exposing the necessary information via CSSOM", which clashes with your proposal in the first post of not exposing it via CSSOM.
I did. Exposing it via the CSS OM doesn't mean exposing it via every single CSS OM API. If .style does the most commonly needed thing, and .styleMap gives you all the information, that sounds like it would meet your requirements?
I would be strongly opposed to doing this as a rule.
That said, there may be value in having an @-rule as well, as sugar for applying !revertable to a bunch of declarations. But as it was pointed out, it should probably not be done from the start, so that authors don’t use it to wrap all their declarations without thinking. The entire reason !revertable might work is because the idea is an !flag is not going to be used everywhere.
I apologize if this was answered in the minutes, I had some trouble understanding all of it... but why revert-rule and not revert-declaration? Does it actually revert all the declarations in the rule as soon as one property is set to that value? If so, that sounds really surprising.
Ah, I just thought about it and can see why revert-rule makes sense. It reverts the property's value to whatever the previous rule that matches sets it to, kinda like how revert-layer reverts it to what the @layer below the current one sets it to.
Still, I wonder if a simpler keyword like cancel would make more sense, because it's basically used to cancel the current declaration, right?
Ah, so the name is not actually counterintuitive, but the feature is, IMO. 😅 What's the reason for giving any single declaration the ability to affect all the declarations of the entire rule it's in? Seems like a first in CSS. Does it include declarations in parent rules, in the case of nesting?
See my comments and meeting minutes where I explained why just cancelling the current declaration shouldn't be done with style rules (it would need to be a new kind of rule).
Also, I didn't say revert-rule cancels ALL declarations in the current rule. It cancels declarations for the same property, or for properties that share a computed value.
I believe the specification should explicitly state that revert-rule does not support reverting within a “declaration block.”
I only discovered this after carefully reviewing the meeting minutes, and it is easily misunderstood.
If I'm not mistaken, in the following style, the color ultimately isn't green.
.foo{color: green;color:var(--unknow, revert-rule);/* ❌ Cannot revert to green */}
It will benefit from a note & example in the spec for sure.
A really great point about preprocessors! They will need to learn not to remove/combine this for sure when minifying it. Some minifiers, for example, could keep both declarations but combine them into one rule, which will be incorrect.
That is workaroundable on the author's side by modifying one of the rules to be different, like
It will benefit from a note & example in the spec for sure.
Adding an empty & {} also makes color: green take effect(Chrome 147.0.7715.0). I think this part of the specification should include some clarification. cc @andruud
Activity
andruud commentedon Jun 14, 2024
There's overlap here with the ideas in #1594.
Ideally, we'd just not do that, and make it always possible to revert to the previous "winner" of the cascade (using a keyword). We'd need to investigate the performance implications of this, though.
LeaVerou commentedon Jun 14, 2024
That’s the idea for the opt-in: that authors would not be doing this for every single declaration, so the performance implications should be minimal.
Loirooriol commentedon Jun 14, 2024
Assuming an horizontal writing mode, should this revert to 2px or 1px? I guess 2px like
revert-layerwould do in different layers, but it seems extra annoying for CSSOM.I wonder if it would make more sense to add an entirely new rule like
LeaVerou commentedon Jun 15, 2024
This seems orthogonal to the issue we’re discussing? It would revert to whatever this would revert to:
Not sure how UAs handle the aliasing, but that doesn't seem particularly difficult to define. They'd probably keep both around?
I would be strongly opposed to doing this as a rule. Rules are far more heavyweight, scoping has to be defined from scratch, and authors cannot port knowledge about it from other parts of CSS. @-rules should be a last resort, not the first thing we reach for because defining syntax with good ergonomics is hard.
LeaVerou commentedon Jun 15, 2024
Agenda+ since I had some discussions with implementers at the CSS WG meeting last week that indicated this is very implementable.
Loirooriol commentedon Jun 15, 2024
It isn't orthogonal. If we are only reverting to the same property, we could just shift down all declarations for the same property to the last one, then store the values together as a list, say that
getPropertyValueprovides the last one, and addgetPropertyValuesto get all of them. Similar for the setter and the priority. But we can at least keep the same indexing as now.However, if we can revert to other properties, we can't keep assuming that a given property can only appear at most at one index. So it seems the API and the data structures used by browsers will need considerably bigger changes.
Well, I would be strongly opposed to not exposing the necessary information via CSSOM.
And it doesn't seem great to pollute
CSSStyleDeclarationwith several things that aren't needed by normal style rules.LeaVerou commentedon Jun 16, 2024
Most aliases are known in advance. The only complication with the issue you're pointing out is that the aliasing can be dynamic. These cases are sufficiently few they can just be stored in a data structure (if they aren’t already).
Nothing is polluting
CSSStyleDeclaration, please read the first post more carefully?But as a general principle, the ergonomics of the language itself are more important than CSS OM ergonomics. That doesn't mean the CSS OM doesn't matter, but the weightings of tradeoffs are different.
Monknow commentedon Jun 25, 2024
Even if an at-rule and a
!-flag are both present after parse time, I think an at-rule would prompt users to put all their styles inside the block, instead of narrowing down which properties they want to enforce the revertable behavior.Besides, as specified on the original issue at #5319, the fallback property may be on another CSS rule (or even on third-party styles), like the following:
If the rule with the IACVT is more specific, the declaration on the lesser specific rule gets thrown away. If I understand your approach correctly, both declarations would need to be in the at-rule, which is harder if they are in different rules.
I think putting a
!-flag (or even the initial proposal for a keyword) after the custom property that may be IACVT is cleaner and gives the user the necessary control.Loirooriol commentedon Jun 25, 2024
@Monknow No. When the second winner of the cascade is in another rule, then it's no different than
!revertable. It's not thrown away at parse time, it's just a matter of discussion whether browsers can afford to keep it during the cascade or not.The problem with normal rules is that duplicate declarations for the same properties get overridden at parse time. So we need a different data structure. Then a different kind of rule may be cleaner.
@LeaVerou Please read my comment more carefully: "I would be strongly opposed to not exposing the necessary information via CSSOM", which clashes with your proposal in the first post of not exposing it via CSSOM.
LeaVerou commentedon Jul 23, 2024
I did. Exposing it via the CSS OM doesn't mean exposing it via every single CSS OM API. If
.styledoes the most commonly needed thing, and.styleMapgives you all the information, that sounds like it would meet your requirements?That said, there may be value in having an @-rule as well, as sugar for applying
!revertableto a bunch of declarations. But as it was pointed out, it should probably not be done from the start, so that authors don’t use it to wrap all their declarations without thinking. The entire reason!revertablemight work is because the idea is an !flag is not going to be used everywhere.16 remaining items
benface commentedon Feb 25, 2025
I apologize if this was answered in the minutes, I had some trouble understanding all of it... but why
revert-ruleand notrevert-declaration? Does it actually revert all the declarations in the rule as soon as one property is set to that value? If so, that sounds really surprising.benface commentedon Feb 25, 2025
Ah, I just thought about it and can see why
revert-rulemakes sense. It reverts the property's value to whatever the previous rule that matches sets it to, kinda like howrevert-layerreverts it to what the @layer below the current one sets it to.Still, I wonder if a simpler keyword like
cancelwould make more sense, because it's basically used to cancel the current declaration, right?Loirooriol commentedon Feb 25, 2025
No, it doesn't just cancel the current declaration. It reverts to another rule, so it can also cancel other declarations in the current rule.
benface commentedon Feb 25, 2025
Ah, so the name is not actually counterintuitive, but the feature is, IMO. 😅 What's the reason for giving any single declaration the ability to affect all the declarations of the entire rule it's in? Seems like a first in CSS. Does it include declarations in parent rules, in the case of nesting?
benface commentedon Feb 25, 2025
So if I'm understanding it right, in this example:
The button's background color would be red on hover only?
Loirooriol commentedon Feb 25, 2025
See my comments and meeting minutes where I explained why just cancelling the current declaration shouldn't be done with style rules (it would need to be a new kind of rule).
Also, I didn't say
revert-rulecancels ALL declarations in the current rule. It cancels declarations for the same property, or for properties that share a computed value.benface commentedon Feb 25, 2025
Ahhhh, my bad. Thank you @Loirooriol, I understand now.
yisibl commentedon Oct 24, 2025
Blink implements the
revert-rulehere: https://chromium-review.googlesource.com/c/chromium/src/+/6884901cdoublev commentedon Nov 4, 2025
@andruud, did you intentionally omit to accept
revert-ruleinallproperty? or is it simply an oversight?andruud commentedon Nov 4, 2025
@cdoublev Thanks, that's just an oversight. Will fix.
yisibl commentedon Jan 29, 2026
I believe the specification should explicitly state that
revert-ruledoes not support reverting within a “declaration block.”I only discovered this after carefully reviewing the meeting minutes, and it is easily misunderstood.
If I'm not mistaken, in the following style, the color ultimately isn't green.
yisibl commentedon Jan 29, 2026
Additionally, can CSS preprocessors safely perform polyfills? See parcel-bundler/lightningcss#580 (comment)
kizu commentedon Jan 29, 2026
@yisibl Yep, it is a “gotcha” based on how we serialize things, easily workaroundable as
It will benefit from a note & example in the spec for sure.
A really great point about preprocessors! They will need to learn not to remove/combine this for sure when minifying it. Some minifiers, for example, could keep both declarations but combine them into one rule, which will be incorrect.
That is workaroundable on the author's side by modifying one of the rules to be different, like
But it is something to watch out for.
yisibl commentedon Mar 4, 2026
Adding an empty
& {}also makescolor: greentake effect(Chrome 147.0.7715.0). I think this part of the specification should include some clarification. cc @andruud[-][css-cascade][css-syntax] New `!revertable` flag to mark a declaration as "can be reverted when IACVT"[/-]