> All in One 586: Lightly Poking at the CSS if() Function in Chrome 137

Ads

Tuesday, June 24, 2025

Lightly Poking at the CSS if() Function in Chrome 137

We’ve known it for a few weeks now, but the CSS if() function officially shipped in Chrome 137 version. It’s really fast development for a feature that the CSSWG resolved to add less than a year ago. We can typically expect this sort of thing — especially one that is unlike anything we currently have in CSS — to develop over a number of years before we can get our dirty hands on it. But here we are!

I’m not here to debate whether if() in CSS should exist, nor do I want to answer whether CSS is a programming language; Chris already did that and definitely explained how exhausting that fun little argument can be.

What I am here to do is poke at if() in these early days of support and explore what we know about it today at a pretty high level to get a feel for its syntax. We’ll poke a little harder at it in another upcoming post where we’ll look at a more heady real-world example.

Yes, it’s already here!

Conditional statements exist everywhere in CSS. From at-rules to the parsing and matching of every statement to the DOM, CSS has always had conditionals. And, as Lea Verou put it, every selector is essentially a conditional! What we haven’t had, however, is a way to style an element against multiple conditions in one line, and then have it return a result conditionally.

The if() function is a more advanced level of conditionals, where you can manipulate and have all your conditional statements assigned to a single property.

.element {
  color: if(style(--theme: dark): oklch(52% 0.18 140); else: oklch(65% 0.05 220));
}

How does if() work?

Well before Chrome implemented the feature, back in 2021 when it was first proposed, the early syntax was like this:

<if()> = if( <container-query>, [<declaration-value>]{1, 2} )

Now we’re looking at this instead:

<if()> = if(
  [<if-statement>: <result>]*;
  <if-statement>: <result> ;?
)

Where…

  • The first <if-statement> represents conditions inside either style()media(), or supports() wrapper functions. This allows us to write multiple if statements, as many as we may desire. Yes, you read that right. As many as we want!
  • The final <if-statement> condition (else) is the default value when all other if statements fail.

That’s the “easy” way to read the syntax. This is what’s in the spec:

<if()> = if( [ <if-branch> ; ]* <if-branch> ;? )
<if-branch> = <if-condition> : <declaration-value>?
<if-condition> = <boolean-expr[ <if-test> ]> | else
<if-test> =
  supports( [ <ident> : <declaration-value> ] | <supports-condition> )
  media( <media-feature> | <media-condition> ) |
  style( <style-query> )

A little wordy, right? So, let’s look at an example to wrap our heads around it. Say we want to change an element’s padding depending on a given active color scheme. We would set an if() statement with a style() function inside, and that would compare a given value with something like a custom variable to output a result. All this talk sounds so complicated, so let’s jump into code:

.element {
  padding: if(style(--theme: dark): 2rem; else: 3rem);
}

The example above sets the padding to 2rem… if the --theme variable is set to dark. If not, it defaults to 3rem. I know, not exactly the sort of thing you might actually use the function for, but it’s merely to illustrate the basic idea.

Make the syntax clean!

One thing I noticed, though, is that things can get convoluted very very fast. Imagine you have three if() statements like this:

:root {
  --height: 12.5rem;
  --width: 4rem;
  --weight: 2rem;
}

.element {
  height: if(
    style(--height: 3rem): 14.5rem; style(--width: 7rem): 10rem; style(--weight: 100rem): 2rem; else: var(--height)
  );
}

We’re only working with three statements and, I’ll be honest, it makes my eyes hurt with complexity. So, I’m anticipating if() style patterns to be developed soon or prettier versions to adopt a formatting style for this.

For example, if I were to break things out to be more readable, I would likely do something like this:

:root {
  --height: 12.5rem;
  --width: 4rem;
  --weight: 2rem;
}

/* This is much cleaner, don't you think? */
.element {
  height: if(
    style(--height: 3rem): 14.5rem; 
    style(--width: 7rem): 10rem; 
    style(--weight: 100rem): 2rem; 
    else: var(--height)
  );
}

Much better, right? Now, you can definitely understand what is going on at a glance. That’s just me, though. Maybe you have different ideas… and if you do, I’d love to see them in the comments.

Here’s a quick demo showing multiple conditionals in CSS for this animated ball to work. The width of the ball changes based on some custom variable values set. Gentle reminder that this is only supported in Chrome 137+ at the time I’m writing this:

The supports() and media() statements

Think of supports() the same way you would use the @supports at-rule. In fact, they work about the same, at least conceptually:

/* formal syntax for @supports */
@supports <supports-condition> {
  <rule-list>
}

/* formal syntax for supports() */
supports( [ <ident> : <declaration-value> ] | <supports-condition> )

The only difference here is that supports() returns a value instead of matching a block of code. But, how does this work in real code?

The <ident>: <declaration-value> you see here is, in this case, the property name: property value e.g. display: flex.

Let’s say you want to check for support for the backdrop-filter property, particularly the blur() function. Typically, you can do this with @supports:

/* Fallback in case the browser doesn't support backdrop-filter */
.card {
  backdrop-filter: unset;
  background-color: oklch(20% 50% 40% / 0.8);
}

@supports (backdrop-filter: blur(10px)) {
  .card {
    backdrop-filter: blur(10px);
    background-color: oklch(20% 50% 40% / 0.8);
  }
}

But, with CSS if(), we can also do this:

.card {
  backdrop-filter: if(
    supports(backdrop-filter: blur(10px)): blur(10px);
    else: unset
  );
}

Note: Think of unset here as a possible fallback for graceful degradation.

That looks awesome, right? Multiple conditions can be checked as well for supports() and any of the supported functions. For example:

.card {
  backdrop-filter: if(
    supports(backdrop-filter: blur(10px)): blur(10px);
    supports(backdrop-filter: invert(50%)): invert(50%);
    supports(backdrop-filter: hue-rotate(230deg)): hue-rotate(230deg);;
    else: unset
  );
}

Now, take a look at the @media at-rule. You can compare and check for a bunch of stuff, but I’d like to keep it simple and check for whether or not a screen size is a certain width and apply styles based on that:

h1 {
  font-size: 2rem;
}

@media (min-width: 768px) {
  h1 {
    font-size: 2.5rem;
  }
}

@media (min-width: 1200px) {
  h1 {
    font-size: 3rem;
  }
}

The media() wrapper works almost the same way as its at-rule counterpart. Note its syntax from the spec:

/* formal syntax for @media */
@media <media-query-list> {
  <rule-list>
}

/* formal syntax for media() */
media( <media-feature> | <media-condition> )

Notice how at the end of the day, the formal syntax (<media-query>) is the same as the syntax for the media() function. And instead of returning a block of code in @media, you’d have something like this in the CSS inline if():

h1 {
  font-size: if(
    media(width >= 1200px): 3rem;
    media(width >= 768px): 2.5rem;
    else: 2rem
  );
}

Again, these are early days

As of the time of this writing, only the latest update of Chrome supports if()). I’m guessing other browsers will follow suit once usage and interest come in. I have no idea when that will happen. Until then, I think it’s fun to experiment with this stuff, just as others have been doing:

Experimenting with early features is how we help CSS evolve. If you’re trying things out, consider adding your feedback to the CSSWG and Chromium. The more use cases, the better, and that will certain help make future implementations better as well.

Now that we have a high-level feel for the if()syntax, we’ll poke a little harder at the function in another article where we put it up against a real-world use case. We’ll link that up when it publishes tomorrow.


Lightly Poking at the CSS if() Function in Chrome 137 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



from CSS-Tricks https://ift.tt/nFQhi1K
via IFTTT

No comments:

Post a Comment

Lightly Poking at the CSS if() Function in Chrome 137

We’ve known it for a few weeks now, but the CSS if() function officially shipped in Chrome 137 version . It’s really fast development for a...