If you’ve ever written a lot of CSS, you know how easy it is to repeat yourself. Maybe you’ve copied the same calc() formula over and over, or you’ve wished there was a simpler way to reuse a bit of logic, like doubling a number, adjusting a color’s opacity, or creating responsive spacing.
Well, CSS is finally getting something that helps with that: custom functions using the new @function rule.
The cool part is that this happens natively in CSS, no preprocessors or JavaScript needed. It’s a big step forward that makes CSS more powerful, reusable, and easier to maintain, especially for large projects and design systems.
In this article, we’ll break down what @function is, how it works, why it’s useful, and how you can start experimenting with it today.
What is the @function rule in CSS?
The new @function rule allows you to create your own custom CSS functions. This means you can name a piece of logic and reuse it anywhere in your stylesheet.
If that sounds a little abstract, think of it like this: In JavaScript, you can write a function like double(20) that returns 40. Now, CSS is getting the same kind of power. You can make your own CSS function that does the same thing directly inside your CSS.
Here’s what it looks like:
@function --double(--x) {
result: calc(var(--x) * 2);
}
.box {
width: --double(20px);
}
What’s happening here:
@functiontells CSS you’re creating a custom function.--doubleis the name of your function (it starts with--like custom properties).--xis a parameter — basically a value that you pass in.result:is what your function returns — in this case, the calculation that doubles the number.
When the browser reads this, it knows that --double(20px) means calc(20px * 2), so the final width becomes 40px.
Core features and syntax details
The @function rule might look fancy at first, but once you understand the basics, it’s actually very logical. Let’s go through each important part step by step.
1. Naming rules
When you create a function in CSS, the name must start with two dashes --, just like custom properties. For example:
@function --my-function(--value) {
result: calc(var(--value) * 2);
}
You can call it whatever you like, as long as:
- It starts with
-- - It only contains letters, numbers, and hyphens
- It’s unique within your stylesheet (you can’t have two functions with the same name in the same layer)
So names like --double, --spacing, or --theme-color are all valid.
2. Parameters (with or without default values)
Parameters are like “inputs” your function can take. For example, in this function:
@function --add-margin(--size) {
result: calc(var(--size) + 10px);
}
--size is the parameter. Whatever you pass in will replace it.
You can also give parameters default values, so your function still works even if you don’t pass anything in:
@function --add-margin(--size: 10px) {
result: calc(var(--size) + 10px);
}
.box {
margin: --add-margin(); /* uses default 10px */
}
That’s super useful when you want your function to have a “fallback” value.
3. Return values (the result: descriptor)
The line that starts with result: tells CSS what your function should return. Whatever value you write after result: becomes the function’s output. Example:
@function --double(--x) {
result: calc(var(--x) * 2);
}
You can even use other functions, variables, or complex logic inside the result.
If you write more than one result: inside the same function (for example, under different media queries), the last one wins, just like in normal CSS.
4. Types and type checking
CSS functions can also define types for parameters. This means you can tell CSS what kind of value you expect, like a number, color, or length, and it’ll check that for you. For example:
@function --fade(--color <color>, --opacity <number>: 0.5) returns <color> {
result: color-mix(in srgb, var(--color), transparent var(--opacity));
}
Here’s what’s happening:
--colormust be a color--opacitymust be a number, and defaults to0.5if not providedreturns <color>means the result must also be a color
This makes your CSS functions more predictable and prevents weird results.
5. Logic inside functions
This is where things get interesting. CSS functions can also include conditional logic and media or container queries inside them. For example, you can use the new if() function to make decisions:
@function --theme-color(--is-dark) {
result: if(var(--is-dark) == true, black, white);
}
That means your function can return different values depending on conditions, like theme, screen size, or container width.
You can even use media or container queries inside your function:
@function --responsive-font(--base-size) {
result: var(--base-size);
@media (min-width: 800px) {
result: calc(var(--base-size) * 1.2);
}
}
This function increases the font size only on larger screens — all inside the function!
6. Calling functions
Once your function is defined, using it is simple: just call it by name, with parentheses:
.element {
width: --double(30px);
}
You can use it anywhere a normal CSS value would go. For example, inside other functions, within calc(), in shorthand properties, and so on.
7. Cascade and layer behavior
Just like CSS variables, functions also follow the cascade. That means if you define two functions with the same name, the one that appears later (or in a higher-priority layer) will take effect. For example:
@layer defaults {
@function --color(--name) {
result: blue;
}
}
@layer theme {
@function --color(--name) {
result: red;
}
}
.box {
color: --color();
}
Here, the theme layer overrides the defaults one, so the color becomes red. This lets you customize or override functions across different layers, which is perfect for theming or large design systems.
Practical examples
Now that you know how @function works, let’s look at some real examples that show how powerful and useful it can be in everyday CSS.
These are simple, practical cases that solve common problems, like converting units, adjusting colors, or making text fluid.
1. Unit conversion (px → rem)
Have you ever found yourself constantly converting pixels to rem? This function can do that math for you automatically.
@function --to-rem(--px <length>) returns <length> {
result: calc(var(--px) / 16);
}
.text {
font-size: --to-rem(24px);
}
Now, when you pass in a pixel value like 24px, the function divides it by 16 (the usual base font size) and you get 1.5rem.
Now you can use --to-rem() anywhere, and your conversions are automatic and consistent.
2. Color manipulation (Add transparency)
If you need to make a color slightly transparent without repeating the same rgba() formulas, here’s a custom function for that:
@function --with-opacity(--color <color>, --alpha <number>: 0.8) returns <color> {
result: color-mix(in srgb, var(--color), transparent var(--alpha));
}
.card {
background-color: --with-opacity(#007bff, 0.2);
}
In the code above, --color is your base color, --alpha is how transparent you want it (default is 0.8). The function then combines the color with transparency to produce a softer version.
You can reuse this function for any color and it’s perfect for hover states, overlays, and subtle backgrounds.
3. Fluid Typography
One of the most common needs in modern CSS is the ability to scale font sizes with the screen width. Here’s how you can make your own function for that:
@function --fluid-type(--min <length>, --max <length>) returns <length> {
result: clamp(var(--min), 2vw + 1rem, var(--max));
}
h1 {
font-size: --fluid-type(1.5rem, 3rem);
}
The function above uses clamp() to set a min, preferred, and max value. As the viewport grows, the font scales smoothly between those limits.
This keeps your text readable and beautiful on any screen, all wrapped up in one neat, reusable function.
Each of these examples demonstrates how @function enables you to reuse logic, avoiding code repetition and maintaining clean, readable, and flexible CSS.
Wrapping up
The new @function rule is one of the most exciting updates to CSS in years.
That said, this feature is still very new and not fully supported everywhere yet. As of now, it primarily works in the latest versions of Chromium-based browsers, such as Chrome and Edge (starting from version 139). Support for Firefox and Safari is still in progress, so you’ll want to treat @function as experimental until adoption grows.
Even with limited availability, it’s worth exploring today. Try it out in a test project, see how it fits your workflow, and start preparing for a future where CSS can do more by itself.
Frequently Asked Questions
What security measures are essential for CSS hosting?
Key security measures for CSS hosting include SSL/TLS encryption, regular software updates, firewalls, and protection against DDoS attacks. These features safeguard your CSS files and the overall integrity of your website.
How do CSS3 transitions and animations enhance web interactivity?
CSS3 transitions allow smooth transitions between different states of an element, while animations enable the creation of dynamic movement and effects. These features enhance user engagement by adding interactivity and visual interest to web interfaces.
Are HTML5 and CSS3 important for mobile web development?
Absolutely. HTML5 and CSS3 enable responsive design, ensuring websites adapt to different screen sizes and devices. This is crucial for delivering a consistent and user-friendly experience on mobile devices.
How does CSS hosting handle scalability for high-traffic websites?
CSS hosting typically employs scalable infrastructure, like cloud hosting, which can dynamically allocate resources to handle increased traffic. This ensures your site remains fast and reliable, even during traffic surges.
Joel Olawanle is a Software Engineer and Technical Writer with over three years of experience helping companies communicate their products effectively through technical articles.
View all posts by Joel Olawanle