CSS Finally Got Inline Conditionals

I’ve been digging into some of the newer features landing in CSS, and inline conditionals with the if() function jumped out as one of the more interesting ones. The idea of writing a condition right next to the property it affects, instead of opening a separate @media block ten lines away, sounds useful. So this post is my attempt at summarizing what I found. I hope it helps if you’re trying to figure out what if() actually does and where it fits.

What It Actually Does

The shape is condition, colon, value, with an optional else branch:

property: if(<condition>: <value>; else: <fallback>;);

You evaluate something, you get back a value, and the property uses that value. The else: branch is optional. If you leave it off and the condition fails, the property falls back to its inherited or initial value.

That’s it.

What makes it powerful is what you can put in that condition slot. Three kinds of queries are supported: media() for viewport and device conditions, style() for custom property values on the element, and supports() for feature detection. The same things you’ve always been able to ask CSS, but now you can ask them inline, right next to the property they affect.

Theming Without the Yo-Yo

Dark mode is the most obvious win.

.card {
  background-color: white;
  color: black;
}

@media (prefers-color-scheme: dark) {
  .card {
    background-color: #333;
    color: white;
  }
}

And here’s the same thing with if():

.card {
  background-color: if(media(prefers-color-scheme: dark): #333; else: white;);
  color: if(media(prefers-color-scheme: dark): white; else: black;);
}

The logic lives next to the property. You don’t have to hunt down a separate block to figure out what happens in dark mode. When you change the light color, the dark color is right there staring at you. That’s a real maintenance win, especially in a stylesheet that’s been touched by five different people.

Variants Without Modifier Classes

This is the example that makes the case best. Component libraries are drowning in modifier classes. .btn-primary, .btn-danger, .btn-success, on and on. Every one of them is just a different background color and maybe a border.

With if() and a custom property, you can collapse the whole thing:

.button {
  padding: 10px 20px;
  border-radius: 6px;
  color: white;
  background-color: if(
    style(--variant: danger): red;
    style(--variant: success): green;
    else: blue;
  );
}
<button class="button">Submit</button>
<button class="button" style="--variant: danger;">Delete</button>

No JavaScript reading props and toggling class names. No BEM modifier soup. You set a variable, the CSS reacts. The component owns its own logic.

Feature Detection Inline

The same pattern works for graceful degradation when you want a newer feature with a fallback:

.element {
  display: if(supports(display: grid): grid; else: flex;);
  color: if(
    supports(color: lch(75% 0 0)): lch(75% 0 0);
    else: rgb(185 185 185);
  );
}

This used to require a dedicated @supports block with the property repeated inside. Now it doesn’t.

Observations

A few things are happening here that go deeper than syntactic sugar.

The first is bloat reduction. A component that used to need a base class plus four modifier classes plus a media query block can be one selector. Multiply that across a design system and the savings get real.

The second is encapsulation. A component’s stylesheet can carry its own logic without relying on a JavaScript framework to compute the right class name and shove it into the DOM. The CSS engine is doing the work, natively, and it’s a lot faster at this than your render loop is.

If the logic lives where the value lives, you don’t context-switch to figure out why a property has the value it does. You read the property, you read the condition, you understand it, you move on.

That’s the same reason inline error handling beats a separate try/catch block ten lines away. Co-location is a maintenance superpower.

Browser Support

Browser support is still narrow. Chrome shipped if() in version 137, but Firefox and Safari haven’t followed yet, so this isn’t something to drop into a production stylesheet without a fallback. The pattern is to declare a plain value first and then override with if(), so non-supporting browsers ignore the line they don’t understand:

.card {
  background-color: white;
  background-color: if(media(prefers-color-scheme: dark): #333; else: white;);
}

The syntax has also shifted through CSS Working Group drafts, so older articles you find about if() may show a comma-ternary form that no longer works. Check MDN before copying anything.

But the direction is right. CSS has been quietly absorbing more and more of the work we used to push to JavaScript, and if() is one of the bigger steps in that direction. I’ll probably keep poking at it.

Sources

I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].

/ Web development / Css / Frontend