CSS Gets a Conditional Function
The CSS Working Group recently resolved to add an if() function to the CSS Values Module Level 5 specification, following a proposal from Lea Verou. Verou demonstrated the potential of inline conditionals in a post on X:
background: if(style(–variant: success), var(–green));
The resolution isn't a finished feature — it's a green light for the CSSWG to develop a draft specification. Browser implementations are still a long way off, and the details are likely to shift during the process.
Why Inline Conditionals Matter
CSS has always been a conditional language — every selector is essentially a conditional, and the Cascade is the mechanism for evaluating those conditions. What's new with if() is the ability to write conditions inline, within a single declaration, rather than relying on separate rules with selectors.
The idea is not entirely novel. A similar proposal from 2018 didn't gain traction, in part because the syntax for conditions was largely undefined. This time, however, CSS already has a mature conditional mechanism in place: style queries. The conditions used by if() can reference the same syntax, plus media() and supports() functions drawn from Tab Atkins's @when proposal.
The Proposed Syntax
The basic structure looks like this:
<if()> = if( <container-query>, [<declaration-value>]{1, 2} )
where the first argument is a condition, the second is the value to use when the condition matches, and the optional third argument is the fallback value. If no third argument is provided, it's treated as an empty token stream. Values can be nested to create multiple branches.
When there's no fallback, the declaration resolves to an empty value rather than a default, which keeps the syntax readable:
.element {
background-color:
/* If the style declares the following custom property: */
if(style(--variant: success),
var(--color-green-50) /* Matched condition */
);
}
Nesting can get deep. A more verbose form might have an if() inside an if() to handle multiple cases:
background-color: if(
style(--variant: success), var(--color-success-60),
if(style(--variant: warning), var(--color-warning-60),
if(style(--variant: danger), var(--color-danger-60),
if(style(--variant: primary), var(--color-primary)
)
),
)
);
Lea Verou suggests a flatter alternative where conditions are declared outside the nested structure — each branch gets its own condition rather than building a nested tree:
<if()> = if(
[ <container-query>, [<declaration-value>]{2} ]#{0, },
<container-query>, [<declaration-value>]{1, 2}
)
That same concept yields a flatter structure:
background-color: if(
style(--variant: success), var(--color-success-60),
style(--variant: warning), var(--color-warning-60),
style(--variant: danger), var(--color-danger-60),
style(--variant: primary), var(--color-primary)
);
Ties to Style Queries
The conditions in if() rely on the same style query mechanism used in container queries. Container queries implicitly assume size dimensions:
.element {
background: var(--color-primary);
/* Condition */
@container parent (width >= 60ch) {
/* Applied styles */
background: var(--color-success-60);
}
}
When the style() function is used instead, container queries become style queries:
.element {
background: orangered;
/* Condition */
@container parent style(--variant: success) {
/* Applied styles */
background: dodgerblue;
}
}
Viewed in isolation, style queries are an easy target for the question "What are they good for?" In the context of if(), though, they're clearly a building block for a broader conditional system.
Some challenges remain. Tab Atkins describes a possible ambiguity between the matched condition and the default value in certain cases. And while conditions like supports() and media() should be feasible, size queries present a problem:
I don't see why we couldn't do
supports()andmedia(), but size queries would cause cycles with layout that are hard/impossible to even detect. (That's why we needed the restrictions we currently have for size CQs in the first place.)
Existing Workarounds
Developers have long crafted approaches to fake conditional custom properties:
- Treating a custom property as a Boolean — applying styles based on whether it equals
0or1. - The "custom property toggle trick", where a placeholder property is set to a meaningful value based on the presence of another property.
- Container Style Queries, but these can only style a container's descendants, not the container itself — so they can't be used to conditionally apply a value to the element being queried.
Verou's subsequent post on inline conditional statements in CSS today includes a detailed comparison table of these workarounds against the proposed if():
| Method | Input values | Output values | Pros | Cons |
|---|---|---|---|---|
| Binary Linear Interpolation | Numbers | Quantitative | Can be used as part of a value | Limited output range |
| Toggles | var(--alias) (actual values are too weird to expose raw) | Any | Can be used in part of a value | Weird values that need to be aliased |
| Paused animations | Numbers | Any | Normal, decoupled declarations | Takes over animation propertyCascade weirdness |
| Type Grinding | Keywords | Any value supported by the syntax descriptor | High flexibility for exposed APIGood encapsulation | Must insert CSS into light DOM Tedious code (though can be automated with build tools) No Firefox support (though that’s changing) |
| Variable animation name | Keywords | Any | Normal, decoupled declarations | Impractical outside of Shadow DOM due to name clashes Takes over animation propertyCascade weirdness |
References
- What is the MVP for inline conditionals on custom properties? (GitHub Issue #10064)
- Inline conditionals in CSS? (Lea Verou)
- Inline conditionals in CSS, now? (Lea Verou)



