Why CSS Needs Custom Functions
For years, CSS developers have relied on preprocessors like Sass to bring logic and reusability to stylesheets. But now, the platform is catching up. The CSS @function at-rule, part of the CSS Custom Functions and Mixins Module Level 1, lets you define your own functions directly in CSS — no build step required.
Imagine being able to write a function that calculates a progression percentage, adjusts spacing based on a scale, or even returns a color with alpha transparency. With @function, you can encapsulate complex logic and reuse it across your stylesheets.
This isn't just a syntactic sugar. It's a fundamental shift toward more maintainable, type-safe CSS. Let's dive into how it works and what you can do with it today.
Note:
@functionis still experimental. Check browser support before using it in production.

Core Syntax and Practical Examples
Defining a Basic Function
A custom function starts with @function, followed by a --dashed-ident name, optional parameters, and a returns descriptor. Inside, you use the result descriptor to return a value.
/* Define a function that halves any length */
@function --half(--size) returns {
result: calc(var(--size) / 2);
}
/* Use it */
.container {
margin-inline: --half(20px); /* 10px */
}
Type Checking for Safety
You can enforce input types using angle brackets, similar to @property. This catches errors early, especially in large codebases.
/* Only accept numbers, return a percentage */
@function --progression(--current, --total) returns {
result: calc(var(--current) / var(--total) * 100%);
}
.progress-bar {
width: --progression(3, 5); /* 60% */
}
Handling Lists and Defaults
Passing lists is possible by suffixing # and wrapping values in curly braces. Default values are also supported.
/* Calculate range from a list plus an extra value */
@function --get-range(--list#, --n) {
result: calc(max(var(--list)) - min(var(--list)) + var(--n));
}
div {
padding-block: --get-range({10px, 100px, 50px, 25px}, 200px); /* 290px */
}
Nesting Functions and Local Variables
You can nest custom functions and use locally scoped custom properties, keeping your code modular and clean.
@function --square(--n) {
result: calc(var(--n) * var(--n));
}
@function --circle-area(--radius) {
--pi: 3.14159;
result: calc(var(--pi) * --square(var(--radius)));
}
.blob {
width: calc(--circle-area(10) * 1px); /* 314.159px */
}
Using the Cascade for Responsive Logic
Because result follows the CSS cascade, you can use media queries or container queries to return different values.
@function --suitable-font-size() returns {
result: 16px;
@media (width > 1000px) {
result: 20px;
}
}
body {
font-size: --suitable-font-size();
}
Remember: The last valid declaration wins. If you place the fallback after the media query, it will always override it.

Limitations and Gotchas
While @function is powerful, it has strict rules:
- No side effects: You cannot change properties or generate multiple declarations. That's reserved for the proposed
@mixinat-rule. - Circular dependencies: If a function calls itself (directly or indirectly), the browser marks it invalid. Same goes for custom properties that depend on the function.
- Type mismatches: If an argument doesn't match the declared type, the entire function call becomes invalid.
Browser Support and Progressive Enhancement
Currently, @function is only supported behind flags in some browsers. Unsupported browsers ignore it, so you should use fallbacks and @supports for progressive enhancement.
@supports (at-rule(@function)) {
/* Use custom functions */
}
However, note that the at-rule() condition itself has limited support (Chrome 148+ only). For the latest status, check Can I use.

Conclusion and Next Steps
CSS @function is a game-changer for creating maintainable, logic-driven styles. Start experimenting with it in your local projects to get familiar with the syntax and capabilities. Once browser support improves, you'll be ready to adopt it in production.
For a deeper dive into modern CSS features, check out our guide on CSS container queries and practical examples of custom properties.
If you're interested in how to decide between modals and separate pages in UX design, we have a definitive decision tree that might help. And for those working with distributed systems, our PyTorch communication tutorial is a great resource.
Source: CSS-Tricks Almanac: @function