revert vs revert-layer vs unset in Cascade Layers
Five CSS-wide keywords can each be described as “resetting” a property, and in a layered stylesheet they produce five different computed values from the same declaration. Choosing by feel is how a reset ends up applying Times New Roman to a card. This page gives a decision procedure that resolves the choice in one pass, extending revert-layer and cascade rollback under the CSS cascade fundamentals reference.
Prerequisites
You need to know how layer declaration order works and to be able to tell whether a property is inherited — MDN lists this under “Inherited: yes/no” on every property page. The canonical stack is used throughout:
/* WHY: three populated layers give the keywords something to differ about;
with a single layer, revert and revert-layer produce the same answer. */
@layer reset, base, theme, components, utilities;Tooling: DevTools with the Computed tab. No build step.
Step 1: Say what value you want, in words
Every mistake in this area starts with skipping this step. Write the sentence first:
- “the parent’s value” →
inherit - “the value CSS specifies as this property’s default” →
initial - “whichever of those two the property normally uses” →
unset - “the browser’s default styling for this element” →
revert - “whatever my lower layers say” →
revert-layer
What this does: turns a keyword choice into a lookup instead of a guess.
Step 2: Check whether the property inherits
unset is the only keyword whose meaning changes with the property, and that is exactly what makes it dangerous in a reset.
@layer components {
.note {
/* WHY: `color` is inherited, so `unset` here means "inherit" — the note
takes the parent's colour, NOT the theme layer's colour. */
color: unset;
/* WHY: `padding` is not inherited, so `unset` means "initial" — 0px,
discarding every author layer including the design system's spacing. */
padding: unset;
}
}What this does: demonstrates why one keyword produced two unrelated behaviours in a single rule. If you cannot state which branch applies without checking, use an explicit keyword instead.
Step 3: Locate the layer that holds the value you want
revert-layer steps down exactly one layer at a time — it does not search for a value you name.
@layer base { .note { padding: 4px; } }
@layer theme { .note { padding: 8px; } }
@layer components { .note { padding: 16px; } }
@layer utilities {
/* WHY: this lands on `components` (16px), not on `theme` (8px). To reach
`theme`, the components declaration would have to not exist — a rollback
cannot skip a layer that contributes a value. */
.note { padding: revert-layer; }
}What this does: confirms the rollback destination before you rely on it. When the value you want is two layers down, the answer is to restructure — move the intermediate declaration, or set the value explicitly — not to reach for a different keyword.
Step 4: Apply the decision table
| You want | Keyword | Reaches |
|---|---|---|
| The parent element’s value | inherit |
The DOM, not the cascade |
| The property’s spec default | initial |
Nothing in your CSS |
| Default behaviour for this property type | unset |
Parent or spec default |
| The browser’s own styling | revert |
The user-agent origin |
| Your lower layers’ value | revert-layer |
One layer down |
What this does: resolves the choice. Note the asymmetry worth remembering: only revert-layer is aware that layers exist at all. The other four were defined before layers shipped and treat your entire author stack as a single undifferentiated block.
Step 5: Prove the result in the Computed tab
A page that looks right is not proof — several of these keywords coincide in the common case where only one layer sets the property.
// Print the resolved value for each candidate keyword on the same element by
// applying them one at a time. Run in the console with the element selected
// as $0 in DevTools.
['initial', 'inherit', 'unset', 'revert', 'revert-layer'].forEach((kw) => {
const prev = $0.style.padding;
$0.style.padding = kw; // inline style: highest priority
console.log(kw.padEnd(12), getComputedStyle($0).paddingTop);
$0.style.padding = prev; // restore
});What this does: produces five concrete values for one element in one run. Note the inline-style caveat: because the probe writes to element.style, a revert-layer there behaves as revert — inline styles are unlayered. Use it to compare initial, inherit, unset and revert, and test revert-layer from a real rule inside a layer.
Verification
- In the Styles panel, confirm the winning declaration is the one you edited and that its layer annotation matches the layer you intended.
- In the Computed tab, read the resolved value and compare it with the sentence you wrote in Step 1. They should match exactly.
- Toggle the lower layer’s declaration off.
revert-layershould change its result;revert,initialandunsetshould not. That difference is the definitive test of which keyword you actually got.
Troubleshooting
unset produced a value from outside my design system.
: The property is not inherited, so unset resolved to the spec initial value and discarded every author layer. Use revert-layer when the design system’s own lower-layer value is what you want.
revert restored a browser default I did not expect to exist.
: The user-agent stylesheet styles more than most people assume — display, margin, font, list-style, form-control appearance. revert returns all of it. If you only wanted to drop your own top layer, revert-layer is the keyword.
revert-layer and revert behave identically.
: The declaration is in the lowest layer, or in unlayered CSS. In both positions there is no previous author layer, so the rollback continues into the previous origin. Move the rule up a layer if you want a different result.
The keyword had no effect whatsoever.
: A higher-priority declaration is winning — an !important, an unlayered rule, or an inline style. Every CSS-wide keyword is an ordinary declaration and loses the same cascade competitions as any value.
inherit produced nothing visible on a root-level element.
: inherit on an element whose parent has no computed value for that property falls through to the initial value. It is not a cascade tool at all; it reads the DOM.
Complete working example
/* ============================================================
One element, five keywords — copy into a page and inspect
============================================================ */
@layer reset, base, theme, components, utilities;
@layer base {
/* WHY: a value in a low layer gives revert-layer somewhere to land. */
.swatch { padding: 4px; color: #6b5e3e; border: 1px dotted #d4c89a; }
}
@layer theme {
.swatch { padding: 8px; color: #5a6830; }
}
@layer components {
/* The layer directly below `utilities` — the rollback destination. */
.swatch { padding: 16px; color: #3b3522; }
}
@layer utilities {
/* WHY: each modifier isolates one keyword so the computed values can be
compared side by side in DevTools. */
.swatch--initial { padding: initial; } /* → 0px */
.swatch--inherit { padding: inherit; } /* → the parent's padding */
.swatch--unset { padding: unset; } /* → 0px (not inherited) */
.swatch--revert { padding: revert; } /* → the UA default, 0px */
.swatch--rollback { padding: revert-layer; } /* → 16px, from components */
/* WHY: colour IS inherited, so the same five keywords diverge differently —
this is the pair that exposes `unset`'s dual personality. */
.swatch--c-unset { color: unset; } /* → the parent's colour */
.swatch--c-rollback { color: revert-layer; } /* → #3b3522, from components */
}Frequently Asked Questions
Is unset ever the right choice inside a cascade layer?
Yes — when the intent really is “behave as though no author rule had touched this element”. That is a legitimate need for content coming from outside your system, where inherited properties should flow from the container and non-inherited ones should return to their defaults. The moment your intent involves the word “back to our base styles”, unset is wrong, because it is blind to your layer stack.
Why does revert produce different results on inherited and non-inherited properties?
The keyword itself is consistent: it removes the author origin’s contribution and lets the cascade continue from there. What differs afterwards is inheritance. An inherited property with no user-agent rule then takes the parent’s computed value, while a non-inherited one settles on its initial value. The variation comes from the properties, not from the keyword.
Can revert-layer replace every use of !important in an override layer?
It replaces the large majority — every override whose purpose was to cancel a declaration from a lower layer. Two cases survive: an existing !important in another layer, which only an !important rollback can beat, and unlayered author styles, which outrank every layer no matter which keyword you use. Both are better fixed by moving the offending rules into layers than by escalating.
Related
- revert-layer and Cascade Rollback — the full resolution model for the layer-aware keyword
- Using revert-layer to Undo a Component Style — converting a hard-coded override into a rollback
- Cascade Origins, User Agent and User Styles — what
revertactually falls back to - Why Your CSS Reset Isn’t Working With Cascade Layers — the reset-layer failure these keywords are often misapplied to
Up: revert-layer and Cascade Rollback → CSS Cascade Fundamentals & @layer Syntax