The CSS if() Function Has Arrived!

Imagine being able to set CSS properties directly based on conditions — without JavaScript, without preprocessors, without workarounds. With the new if() function in CSS, this is now a reality. The CSS if() function officially shipped in Chrome 137.

For years, we’ve relied on workarounds: JavaScript toggle classes, CSS preprocessor mixins, or endless media query blocks. The if() function puts an end to all that, bringing conditional logic directly into CSS — elegant, performant, and declarative.

How it works:

property: if(
condition-1: value-1;
condition-2: value-2;
condition-3: value-3;
else: default-value
);

The function checks conditions sequentially and applies the first matching value. If no condition matches, the else value is used — exactly as you’d expect from programming languages, but now in pure CSS.

The three capabilities of the if() function

1. Style queries

With style(), you can react to CSS Custom Properties:

.card {
--status: attr(data-status type(<custom-ident>));

border-color: if(
style(--status: pending): royalblue;
style(--status: complete): seagreen;
style(--status: error): crimson;
else: gray
);
}

A single data-status attribute in HTML now controls the entire styling — no more utility classes needed!

2. Media queries

Forget nested media query blocks. With media(), you define responsive values inline:

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

3. Feature detection

Gone are the days of random fallback strategies and hoping things work 😬. With supports(), you check browser features directly in the property:

.element {
border-color: if(
supports(color: lch(0 0 0)): lch(50% 100 150);
supports(color: lab(0 0 0)): lab(50 100 -50);
else: rgb(200, 100, 50)
);
}

Real-world use cases

Dark mode in three lines

body {
--theme: "dark"; /* Toggle via JavaScript or User Preference */

background: if(
style(--theme: "dark"): #1a1a1a;
else: white
);

color: if(
style(--theme: "dark"): #e4e4e4;
else: #333
);
}

Design system status components

.alert {
--type: attr(data-type type(<custom-ident>));

background: if(
style(--type: success): #d4edda;
style(--type: warning): #fff3cd;
style(--type: danger): #f8d7da;
style(--type: info): #d1ecf1;
else: #f8f9fa
);

border-left: 4px solid if(
style(--type: success): #28a745;
style(--type: warning): #ffc107;
style(--type: danger): #dc3545;
style(--type: info): #17a2b8;
else: #6c757d
);
}

Container without media query chaos

.container {
width: if(
media(width >= 1400px): 1320px;
media(width >= 1200px): 1140px;
media(width >= 992px): 960px;
media(width >= 768px): 720px;
media(width >= 576px): 540px;
else: 100%
);

padding-inline: if(
media(width >= 768px): 2rem;
else: 1rem
);
}

Combining with modern CSS features 🤔

.element {
/* With the new light-dark() function */
color: if(
style(--high-contrast: true): black;
else: light-dark(#333, #e4e4e4)
);

/* With CSS Custom Functions (@function) */
padding: if(
style(--spacing: loose): --spacing-function(2);
style(--spacing: tight): --spacing-function(0.5);
else: --spacing-function(1)
);
}

Since support is still growing, you can use this pattern:

.button {
/* Fallback for all browsers */
padding: 1rem 2rem;
background: #007bff;

/* Modern browsers automatically override */
padding: if(
style(--size: small): 0.5rem 1rem;
style(--size: large): 1.5rem 3rem;
else: 1rem 2rem
);

background: if(
style(--variant: primary): #007bff;
style(--variant: success): #28a745;
style(--variant: danger): #dc3545;
else: #6c757d
);
}

Categories: Blog
X