A couple of sirens went off a few weeks in the past when the CSS Working Group (CSSWG) resolved so as to add an if()
conditional to the CSS Values Module Degree 5 specification. It was Lea Verouโs X publish that very same day that caught my consideration:
A historic day for CSS ๐๐
When you write any elements used and/or styled by others, you know the way big that is!
background: if(type(โvariant: success), var(โinexperienced));
Even should you donโt, it will enable issues like:
padding: if(var(โ2xl), 1em, var(โxl) or var(โm),โฆ pic.twitter.com/cXeqwBuXvKโ Lea Verou (@LeaVerou) June 13, 2024
Lea is the one who opened the GitHub subject resulting in the dialogue and in a stroke of coincidence โ or serendipity, maybe โ the decision got here in on her birthday. That needed to be fairly a whirlwind of a day! What did you get on your birthday? โOh, you already know, simply an accepted proposal to the CSS spec.โ Wild, simply wild.
The accepted proposal is a inexperienced gentle for the CSSWG to work on the thought with the intent of circulating a draft specification for additional enter and concerns en path to, hopefully, develop into a advisable CSS function. So, itโs gonna be a scorching minute earlier than any of that is baked, that’s, if it will get totally baked.
However the concept of making use of kinds based mostly on a conditional requirement is tremendous thrilling and value an early have a look at the thought. I scribbled some notes about it on my weblog the identical day Lea posted to X and thought Iโd distill these right here for posterity whereas rounding up extra particulars which have come up since then.
This isnโt a brand new concept
Many proposals are born from beforehand rejected proposals and if()
isn’t any totally different. And, certainly, we’ve gained a number of CSS options in latest days that enable for conditional styling โ :has()
and Container Type Queries being two of the extra apparent examples. Lea even cites a 2018 ticket that appears and reads quite a bit just like the accepted proposal.
The distinction?
Type queries had already shipped, and we may merely reference the identical syntax for circumstances (plusย
media()
ย andยhelps()
ย fromย Tabโsย@when
ย proposal) whereas within the 2018 proposal how circumstances would work was largely undefined.Lea Verou, โInline conditionals in CSS?โ
I like how Lea factors out that CSS goes on to explain how CSS has at all times been a conditional language:
Of usโฆ CSS had conditionals from the very starting. Each selector is actually a conditional!
Lea Verou, โInline conditionals in CSS?โ
True! The Cascade is the car for evaluating selectors and matching them to HTML parts on a web page. What if()
brings to the desk is a strategy to write inline circumstances with selectors.
Syntax
It boils right down to this:
<if()> = if( <container-query>, [<declaration-value>]{1, 2} )
โฆthe place:
- Values will be nested to provide a number of branches.
- If a 3rd argument is just not supplied, it turns into equal to an empty token stream.
All of that is conceptual in the intervening time and nothing is ready in stone. Weโre more likely to see issues change because the CSSWG works on the function. However because it at the moment stands, the thought appears to revolve round specifying a situation, and setting one among two declared kinds โ one because the โdefaultโ type, and one because the โup to dateโ type when a match happens.
.component {
background-color:
/* If the type declares the next customized property: */
if(type(--variant: success),
var(--color-green-50), /* Matched situation */
var(--color-blue-50); /* Default type */
);
}
On this case, weโre in search of a type()
situation the place a CSS variable known as --variant
is asserted and is ready to a worth of success
, and:
- โฆif
--variant
is ready tosuccess
, we set the worth ofsuccess
to--color-green-50
which is a variable mapped to some greenish shade worth. - โฆif
--variant
is just not set tosuccess
, we set the worth of thesuccess
to--color-blue-50
which is a variable mapped to some bluish shade worth.
The default type could be optionally available, so I believe it may be omitted in some instances for barely higher legibility:
.component {
background-color:
/* If the type declares the next customized property: */
if(type(--variant: success),
var(--color-green-50) /* Matched situation */
);
}
The syntax definition up high mentions that we may assist a 3rd argument along with the matched situation and default type that enables us to nest circumstances inside circumstances:
background-color: if(
type(--variant: success), var(--color-success-60),
if(type(--variant: warning), var(--color-warning-60),
if(type(--variant: hazard), var(--color-danger-60),
if(type(--variant: main), var(--color-primary)
)
),
)
);
Oomph, appears like some wild inception is going on in there! Lea goes on to counsel a syntax that may lead to a a lot flatter construction:
<if()> = if(
[ <container-query>, [<declaration-value>]{2} ]#{0, },
<container-query>, [<declaration-value>]{1, 2}
)
In different phrases, nested circumstances are rather more flat as they are often declaredย outdoorsย of the preliminary situation. Identical idea as earlier than, however a special syntax:
background-color: if(
type(--variant: success), var(--color-success-60),
type(--variant: warning), var(--color-warning-60),
type(--variant: hazard), var(--color-danger-60),
type(--variant: main), var(--color-primary)
);
So, relatively than one if()
assertion inside one other if()
assertion, we will lump the entire attainable matching circumstances right into a single assertion.
That is all associated to type queries
Weโre making an attempt to match an if()
situation by querying a componentโs kinds. There isn’t any corresponding measurement()
operate for querying dimensions โ container queries implicitly assume measurement:
.component {
background: var(--color-primary);
/* Situation */
@container dad or mum (width >= 60ch) {
/* Utilized kinds */
background: var(--color-success-60);
}
}
And container queries develop into type queries after we name the type()
operate as an alternative:
.component {
background: orangered;
/* Situation */
@container dad or mum type(--variant: success) {
/* Utilized kinds */
background: dodgerblue;
}
}
Type queries make much more sense to me after theyโre considered within the context of if()
. With out if()
, itโs simple to query the overall usefulness of fashion queries. However on this gentle, itโs clear that type queries are a part of a a lot greater image that goes past container queries alone.
Thereโs nonetheless loads of issues to suss out with the if()
syntax. For instance, Tab Atkins describes a attainable state of affairs that might result in confusion between what’s the matched situation and default type parameters. So, who is aware of how this all shakes out in the long run!
Circumstances supporting different circumstances
As weโve already famous, if()
is way from the one sort of conditional verify already supplied in CSS. What wouldn’t it appear to be to write down an inline conditional assertion that checks for different circumstances, akin to @helps
and @media
?
In code:
background-color: if(
helps( /* and so forth. */ ),
@media( /* and so forth. */ )
);
The problem could be container supporting measurement queries. As talked about earlier, there isn’t any expressย measurement()
ย operate; as an alternative itโs extra like an nameless operate.
@andruudย has aย succinctly describes the problem within the GitHub dialogue:
I donโt see why we couldnโt doย
helps()
ย andยmedia()
, however measurement queries would trigger cycles with format which might be laborious/unimaginable to even detect. (Thatโs why we wanted the restrictions we at the moment have for measurement CQs within the first place.
โCanโt we already do that with [X] strategy?โ
After we had been trying on the syntax earlier, you might have observed that if()
is simply as a lot about customized properties as it’s about conditionals. A number of workarounds have emerged over time to imitate what weโd achieve if()
we may set a customized property worth conditionally, together with:
- Utilizing customized properties as a Boolean to use kinds or not relying on whether or not it is the same asย
0
ย orย1
. (Ana has an exquisite article on this.) - Utilizing a placeholder customized property with an empty worth thatโs set when one other customized property is ready, i.e.ย โthe customized property toggle trickโย as Chris describes it.
- Container Type Queries!ย The issue (in addition to lack of implementation) is that containers solely apply kinds to their descendants, i.e., they can’t apply kinds to themselves after they meet a sure situation, solely its contents.
Lea will get deep into this in a separate publish titled โInline conditional statements in CSS, now?โ that features a desk that outlines and compares approaches, which Iโll merely paste beneath. The reasons are stuffed with advanced CSS nerdery however are extraordinarily useful for understanding the necessity for if()
and the way it compares to the intelligent โhacksโ weโve used for years.
Technique | Enter values | Output values | Execs | Cons |
---|---|---|---|---|
Binary Linear Interpolation | Numbers | Quantitative | Can be utilized as a part of a worth | Restricted output vary |
Toggles | var(--alias) ย (precise values are too bizarre to show uncooked) |
Any | Can be utilized in a part of a worth | Bizarre values that have to be aliased |
Paused animations | Numbers | Any | Regular, decoupled declarations | Takes overย animation ย property
Cascade weirdness |
Sort Grinding | Key phrases | Any worth supported by theย syntax ย descriptor |
Excessive flexibility for uncovered APIGood encapsulation | Should insert CSS into gentle DOM
Tedious code (although will be automated with construct instruments) No Firefox assist (although thatโsย altering) |
Variable animation identify | Key phrases | Any | Regular, decoupled declarations | Impractical outdoors of Shadow DOM as a result of identify clashes
Takes overย Cascade weirdness |
Completely happy birthday, Lea!
Belated by two weeks, however thanks for sharing the spoils of your huge day with us! ๐
References