CSS Custom Functions are coming … and they are going to be a game changer!

Chrome is currently prototyping CSS Functions, which is very exciting!

~

⚠️ This post is about an upcoming CSS feature. You can’t use it … yet.

This feature is currently being prototyped in Chrome Canary and can be tested in Chrome Canary with the Experimental Web Platform Features flag enabled.

~

Chrome is currently prototyping CSS Functions from the css-mixins-1 specification.

A custom function can be thought of as an advanced custom property, which instead of being substituted by a single fixed value, computes its substitution value based on function parameters and the value of custom properties at the point it’s invoked.

Here’s a very simple example (taken from the spec) that should give you an idea of what a custom function looks like:

@function --negate(--value) {
	result: calc(-1 * var(--value));
}

You invoke the function like by calling directly – no need for var() or the like – and can use it anywhere a value is accepted. For example:

:root {
  padding: --negate(1px); /* = -1px */
}

The implementation in Chrome Canary is currently incomplete and there is no shipping date set, but you can already try out the WIP-implementation by enabling the Experimental Web Platform Features flag.

~

I’m very excited about this upcoming feature, as it will open up a lot of possibilities, way more impactful than that --negate example from the spec.

For example: a limitation of the CSS light-dark() function is that it only works with <color> values. Thanks to Custom Functions you can write your own --light-dark() that works with any value.

@function --light-dark(--light, --dark) {
	result: var(--light);
	
	@media (prefers-color-scheme: dark) {
		result: var(--dark);
	}
}

If you are visiting the site in the dark mode, the --dark value will be returned. Otherwise the --light value gets returned.

For example, you can use this --light-dark() to have different font-weightsomething Robin suggests on doing:

:root {
	color-scheme: light dark;
  font-family: "Literata", serif;
	
	color: light-dark(#333, #e4e4e4);
	background-color: light-dark(aliceblue, #333);
	font-weight: --light-dark(500, 300);
}

Here’s a live demo that uses that code (and which also changes the font-size and some border-related properties along with it):

💁‍♂️ Note that the custom --light-dark() is not an exact copy of light-dark(). The built-in light-dark() can return different values based on the used color-scheme of an element whereas --light-dark() relies on the global light/dark preference. Being able to respond to used values is not covered by @function itself. For that we’d also need the CSS if() function, which is also in the making (but not really ready for testing, yet). Container queries inside the function also work – to take the parent context into account – but that is currently not prototyped yet.

UPDATE 2025.03.18: In https://www.bram.us/2025/02/18/css-at-function-and-css-if/ I combine @function and if() to create a custom --light-dark() that behaves exactly like the built-in light-dark().

🏎️ Also note that for <color> values I am still using the built-in light-dark() here, but could have used my custom one as well. I have a hunch that the built-in version performs faster, but that would need a proper benchmark.

~

In this post I’ve limited myself to only a basic-ish example, without covering too much details. Not mentioned for example are default values for the function parameters and how to specify the types for any of those. For that, you can dig into the spec. Note that the spec still has a lot of moving parts, as the spec gets influenced by findings from the prototype Chrome is building.

To follow along with Chrome’s progress of the prototype, subscribe to crbug/325504770 by hitting the star next to its title.

~

Spread the word

Feel free to reshare one of the following posts on social media to help spread the word:

~

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.