files/en-us/web/css/reference/at-rules/@function/index.md
{{SeeCompatTable}}
The @function CSS at-rule enables defining CSS custom functions. Once defined, a custom function can be called using the {{cssxref("<dashed-function>")}} syntax (for example, --my-function(30px, 3)) within any property value.
@function --function-name(<function-parameter>#?) [returns <css-type>]? {
<declaration-rule-list>
}
<function-parameter> = --param-name <css-type>? [ : <default-value> ]?
The different parts of the @function syntax are as follows:
--function-name
-- and is followed by a valid, user-defined identifier. It is case-sensitive.<function-parameter>#? {{optional_inline}}
--param-name
-- and is followed by a valid, user-defined identifier. It is case-sensitive. Function parameters can be considered custom properties that are locally scoped to the function body.<css-type> {{optional_inline}}
type(*)).<default-value> {{optional_inline}}
<css-type> if specified. The default value is separated from the other parts of the parameter definition with a colon (:).[returns <css-type>]? {{optional_inline}}
returns, which defines the accepted return type(s) for the parameter. If this is not specified, any data type will be valid for the parameter (the same as specifying returns type(*)), although bear in mind that the function will be invalid if the return type does not match the type produced by the result descriptor.<declaration-rule-list>
result descriptor, either directly inside the @function at-rule, or inside a nested at-rule.result
CSS custom functions allow you to define reusable sections of logic that will return different values depending on the parameters they accept as inputs and the logic defined inside the function body.
A typical CSS function looks like this:
@function --transparent(--color, --alpha) {
result: oklch(from var(--color) l c h / var(--alpha));
}
The function has a name of --transparent and takes two custom properties as parameters, --color and --alpha, which can be used locally inside the function body. The body contains a single line, which is a result descriptor that defines the value returned by the function. The value of the result descriptor uses CSS relative color syntax to convert the input --color value into an {{cssxref("color_value/oklch")}} color with the alpha channel value specified in the input --alpha value.
You can then call this function anywhere you want to produce a semi-transparent version of an existing color, for example:
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color), 0.8);
}
The function is called by using {{cssxref("<dashed-function>")}} syntax, which is the function name with parentheses on the end. The desired argument values are specified inside the parentheses.
[!NOTE] If multiple CSS functions are given the same name, the function in the stronger cascade {{cssxref("@layer")}} wins. If all of them are in the same layer, the function defined last in the source order wins.
It is possible to specify data types for the function parameters and return types. For example:
@function --transparent(--color <color>, --alpha <number>) returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
Now the function will only produce a valid value if the input arguments are a {{cssxref("<color>")}} and a {{cssxref("<number>")}}, respectively, and the result is a {{cssxref("<color>")}}. If not, for example:
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color), 50%);
}
then the value will become invalid at computed-value time (because the specified --alpha argument is a <percentage> and not a <number> as expected) and the background-color will end up being set to transparent.
You can specify multiple accepted data types using a {{cssxref("type()")}} function with the | symbol as a separator, for example:
@function --transparent(--color <color>, --alpha type(<number> | <percentage>))
returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
With this adjustment, the --transparent(var(--base-color), 50%) function call is now valid.
You can also specify default values for parameters, after a colon at the end of their definition. For example:
@function --transparent(--color <color>, --alpha <number>: 0.8) returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
The --alpha parameter's default value is now 0.8. If you want to use this value, you can omit the second argument when calling the function:
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color));
}
[!NOTE] If an invalid value is passed in as a function argument and a default value is specified in that parameter definition, the invalid value will be ignored, and the default value will be used instead.
In the next example, the --max-plus-x() function expects to be passed a comma-separated list of lengths and a single length as arguments. It uses the CSS {{cssxref("max()")}} function to determine which of the list of lengths is the largest, adds it to the single length, then returns the result.
@function --max-plus-x(--list <length>#, --x <length>) {
result: calc(max(var(--list)) + var(--x));
}
The first argument needs to be a comma-separated list, which could be misinterpreted as three separate arguments. To get around this problem, you can wrap the value in curly braces when passing it into the function call:
div {
width: --max-plus-x({1px, 7px, 2px}, 3px); /* 10px */
}
As we've already seen, function parameters are defined as custom properties, which are then available inside the function body.
You can also specify custom properties inside the function body that will act as locally-scoped constants. In the following example, we define a function called --anim-1s(), which returns an {{cssxref("animation")}} shorthand value where the duration and easing values are always the same, and only the animation name and count are varied.
@function --anim-1s(--animation, --count) {
--duration: 1s;
--easing: linear;
result: var(--animation) var(--duration) var(--count) var(--easing);
}
This kind of usage allows you to write easier, more expressive syntax for animations, provided you know that you always want the duration and easing function to be the same:
animation: --anim-1s(bounce, 2);
It is also worth noting that you can call one custom function from inside another. In such cases, a custom function can access local variables and function parameters from functions higher up in the call stack. Here, the outer function's parameter and local custom property will be available inside the scope of the inner function:
@function --outer(--outer-arg) {
--outer-local: 2;
result: --inner();
}
@function --inner() returns <number> {
result: calc(var(--outer-arg) + var(--outer-local));
}
div {
z-index: --outer(1); /* 3 */
}
In addition, custom properties defined on the same element where the custom function is being called will be available to it:
@function --double-z() returns <number> {
result: calc(var(--z) * 2);
}
div {
--z: 3;
z-index: --double-z(); /* 6 */
}
When a custom property of the same name is defined in multiple places, function parameters override custom properties defined on the same element, and local custom properties defined inside the function body override both. In the following example, the --add-a-b-c() function uses the --a property from the div rule's custom property, the --b property from the function parameter, and the --c local custom property.
@function --add-a-b-c(--b, --c) {
--c: 300;
result: calc(var(--a) + var(--b) + var(--c));
}
div {
--a: 1;
--b: 2;
--c: 3;
z-index: --add-a-b-c(20, 30); /* 321 */
}
You can include more complex logic in functions using constructs such as {{cssxref("@media")}} at-rules and {{cssxref("if()")}} functions. For example, the next function takes two arguments, one for a narrow-screen layout and one for a wide-screen layout. It returns the latter by default, but returns the former when the viewport width is less than 700px wide, as detected using a media query.
@function --narrow-wide(--narrow, --wide) {
result: var(--wide);
@media (width < 700px) {
result: var(--narrow);
}
}
You can include multiple result descriptors to express different results for different logic outcomes.
[!NOTE] CSS functions behave in the same way as the rest of CSS regarding conflict resolution — last in source order wins. Therefore, in the above function, the
resultisvar(--wide)unless the media query test returns true, in which case it is overridden byvar(--narrow).There are no early returns in CSS functions like there are in JavaScript functions. In the above function, if the media query was written first, before the single
resultline, theresultwould always bevar(--wide)because it would overridevar(--narrow)in cases where the media query test returns true.
We could rewrite the CSS custom function to use an if() function instead:
@function --narrow-wide(--narrow, --wide) {
result: if(media(width < 700px): var(--narrow) ; else: var(--wide));
}
{{csssyntax}}
For more examples, see our Using CSS custom functions guide.
@function usageThis example shows a basic function that doubles the value passed into it.
The markup features a {{htmlelement("p")}} element containing some text content:
<p>Some content</p>
In our styles, we first define the CSS custom function. The function is called --double, and accepts a single parameter of any type, which we've called --value. Inside the function body, we include a result descriptor that uses the {{cssxref("calc()")}} function to double the passed argument:
@function --double(--value) {
result: calc(var(--value) * 2);
}
Next, we define a --base-spacing custom property with a value of 10px. We assign that property to the {{cssxref("border-radius")}} value, but then double it for the {{cssxref("padding")}} value using the --double() custom function.
html,
body {
height: 100%;
}
body {
margin: 0;
display: grid;
place-items: center;
font-family: system-ui;
}
p {
--base-spacing: 10px;
border-radius: var(--base-spacing);
padding: --double(var(--base-spacing));
width: 50%;
background-color: wheat;
}
{{ EmbedLiveSample('basic-example', '100%', '150px') }}
{{Specifications}}
{{Compat}}
type() function