@function

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

实验性: 这是一项实验性技术
在生产中使用此技术之前,请仔细检查浏览器兼容性表格

@function CSS @ 规则用于定义 CSS 自定义函数。一旦定义,自定义函数就可以在任何属性值中使用 <dashed-function> 语法(例如,--my-function(30px, 3))来调用。

语法

css
@function --function-name(<function-parameter>#?) [returns <css-type>]? {
  <declaration-rule-list>
}

<function-parameter> = --param-name <css-type>? [ : <default-value> ]?

@function 语法的不同部分如下:

--function-name

函数的标识名称,是一个以 -- 开头,后跟一个有效的、用户定义的标识符的 <dashed-ident>。它区分大小写。

<function-parameter>#? 可选

零个或多个函数参数定义。多个参数定义之间用逗号分隔。每个参数包含:

--param-name

用于标识参数的 CSS 自定义属性名称,是一个以 -- 开头,后跟一个有效的、用户定义的标识符的 <dashed-ident>。它区分大小写。函数参数可以被认为是作用域限于函数体的局部自定义属性。

<css-type> 可选

一个 CSS 数据类型或一个 type() 函数,用于定义参数可接受的数据类型。如果未指定,任何数据类型都对该参数有效(与指定 type(*) 相同)。

<default-value> 可选

一个 CSS 值,指定当调用函数时如果未指定参数,则分配给该参数的默认值。如果指定了 <css-type>,此值必须对其有效。默认值与参数定义的其他部分用冒号(:)分隔。

[returns <css-type>]? 可选

一个 CSS 数据类型或一个 type() 函数,前面有关键字 returns,用于定义参数可接受的返回类型。如果未指定,任何数据类型都对该参数有效(与指定 returns type(*) 相同),但请注意,如果返回类型与 result 描述符产生的类型不匹配,函数将无效。

<declaration-rule-list>

一个或多个 CSS 声明或 @ 规则,用于定义函数的主体,其中包含其逻辑。包含的声明可以包括:

  • CSS 自定义属性,其作用域限于函数体。
  • result 描述符,可以直接在 @function @ 规则内,或在嵌套的 @ 规则内。

描述符

result

一个有效的属性值,定义了 CSS 自定义函数返回的结果。值中包含的表达式会被求值,然后返回结果。

描述

CSS 自定义函数允许你定义可重用的逻辑片段,这些逻辑片段将根据它们接受的输入参数以及函数体内定义的逻辑返回不同的值。

一个典型的 CSS 函数如下所示:

css
@function --transparent(--color, --alpha) {
  result: oklch(from var(--color) l c h / var(--alpha));
}

该函数的名称为 --transparent,并接受两个自定义属性作为参数,--color--alpha,它们可以在函数体内局部使用。函数体包含一行,即一个 result 描述符,它定义了函数返回的值。result 描述符的值使用 CSS 相对颜色语法将输入的 --color 值转换为一个 oklch() 颜色,其 alpha 通道值由输入的 --alpha 值指定。

然后你可以在任何需要生成现有颜色半透明版本的地方调用此函数,例如:

css
section {
  --base-color: #faa6ff;
  background-color: --transparent(var(--base-color), 0.8);
}

该函数通过使用 <dashed-function> 语法来调用,即函数名后跟括号。所需的参数值在括号内指定。

备注: 如果多个 CSS 函数被赋予相同的名称,则在更强的级联层(@layer中的函数获胜。如果它们都在同一层中,则源码顺序中最后定义的函数获胜。

指定数据类型

可以为函数参数和返回类型指定数据类型。例如:

css
@function --transparent(--color <color>, --alpha <number>) returns <color> {
  result: oklch(from var(--color) l c h / var(--alpha));
}

现在,只有当输入参数分别为 <color><number>,并且 result 是一个 <color> 时,该函数才会产生有效值。否则,例如:

css
section {
  --base-color: #faa6ff;
  background-color: --transparent(var(--base-color), 50%);
}

那么该值将在计算值时变得无效(因为指定的 --alpha 参数是一个 <percentage> 而不是预期的 <number>),并且 background-color 最终将被设置为 transparent

你可以使用 type() 函数并以 | 符号作为分隔符来指定多个可接受的数据类型,例如:

css
@function --transparent(--color <color>, --alpha type(<number> | <percentage>))
  returns <color> {
  result: oklch(from var(--color) l c h / var(--alpha));
}

经过此调整后,--transparent(var(--base-color), 50%) 函数调用现在是有效的。

指定默认值

你还可以在参数定义的末尾,用冒号指定参数的默认值。例如:

css
@function --transparent(--color <color>, --alpha <number>: 0.8) returns <color> {
  result: oklch(from var(--color) l c h / var(--alpha));
}

--alpha 参数的默认值现在是 0.8。如果你想使用这个值,可以在调用函数时省略第二个参数:

css
section {
  --base-color: #faa6ff;
  background-color: --transparent(var(--base-color));
}

备注: 如果一个无效的值作为函数参数传入,并且该参数定义中指定了默认值,那么无效值将被忽略,而使用默认值。

将包含逗号的值作为参数传递

在下一个示例中,--max-plus-x() 函数期望传入一个以逗号分隔的长度列表和一个单一长度作为参数。它使用 CSS max() 函数来确定长度列表中的最大值,然后将其与单一长度相加,并返回结果。

css
@function --max-plus-x(--list <length>#, --x <length>) {
  result: calc(max(var(--list)) + var(--x));
}

第一个参数需要是一个逗号分隔的列表,这可能被误解为三个独立的参数。要解决这个问题,你可以在将值传入函数调用时用花括号将其包裹起来:

css
div {
  width: --max-plus-x({1px, 7px, 2px}, 3px); /* 10px */
}

在函数中包含自定义属性

正如我们已经看到的,函数参数被定义为自定义属性,然后在函数体内可用。

你还可以在函数体内指定自定义属性,它们将作为局部作用域的常量。在下面的示例中,我们定义了一个名为 --anim-1s() 的函数,它返回一个 animation 简写值,其中持续时间和缓动值始终相同,只有动画名称和次数是可变的。

css
@function --anim-1s(--animation, --count) {
  --duration: 1s;
  --easing: linear;
  result: var(--animation) var(--duration) var(--count) var(--easing);
}

这种用法允许你为动画编写更简单、更具表现力的语法,前提是你知道你总是希望持续时间和缓动函数是相同的:

css
animation: --anim-1s(bounce, 2);

还值得注意的是,你可以在一个自定义函数内部调用另一个自定义函数。在这种情况下,一个自定义函数可以访问调用栈中更上层函数的局部变量和函数参数。在这里,外部函数的参数和局部自定义属性在内部函数的作用域内将是可用的:

css
@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 */
}

此外,在调用自定义函数的同一元素上定义的自定义属性对该函数也是可用的:

css
@function --double-z() returns <number> {
  result: calc(var(--z) * 2);
}

div {
  --z: 3;
  z-index: --double-z(); /* 6 */
}

当一个同名的自定义属性在多个地方定义时,函数参数会覆盖在同一元素上定义的自定义属性,而在函数体内定义的局部自定义属性会覆盖两者。在下面的示例中,--add-a-b-c() 函数使用了来自 div 规则的自定义属性 --a、来自函数参数的属性 --b,以及局部自定义属性 --c

css
@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 */
}

包含复杂逻辑

你可以使用 @media @ 规则和 if() 函数等结构在函数中包含更复杂的逻辑。例如,下一个函数接受两个参数,一个用于窄屏布局,一个用于宽屏布局。它默认返回后者,但当视口宽度小于 700px 时(通过媒体查询检测),它返回前者。

css
@function --narrow-wide(--narrow, --wide) {
  result: var(--wide);
  @media (width < 700px) {
    result: var(--narrow);
  }
}

你可以包含多个 result 描述符来表达不同逻辑结果的不同返回值。

备注: CSS 函数在冲突解决方面的行为与 CSS 的其余部分相同——源码顺序中最后的获胜。因此,在上面的函数中,resultvar(--wide),除非媒体查询测试返回 true,在这种情况下它被 var(--narrow) 覆盖。

CSS 函数中没有像 JavaScript 函数那样的提前返回。在上面的函数中,如果媒体查询写在前面,在单个 result 行之前,那么 result 将始终是 var(--wide),因为它会在媒体查询测试返回 true 的情况下覆盖 var(--narrow)

我们可以重写这个 CSS 自定义函数来改用 if() 函数:

css
@function --narrow-wide(--narrow, --wide) {
  result: if(media(width < 700px): var(--narrow) ; else: var(--wide));
}

正式语法

@function = 
@function <function-token> <function-parameter>#? ) [ returns <css-type> ]? { <declaration-rule-list> }

<function-parameter> =
<custom-property-name> <css-type>? [ : <default-value> ]?

<css-type> =
<syntax-component> |
<type()>

<default-value> =
<declaration-value>

<syntax-component> =
<syntax-single-component> <syntax-multiplier>? |
'<' transform-list '>'

<type()> =
type( <string> )

<syntax-single-component> =
'<' <syntax-type-name> '>' |
<ident>

<syntax-multiplier> =
'#' |
'+'

<syntax-type-name> =
angle |
color |
custom-ident |
image |
integer |
length |
length-percentage |
number |
percentage |
resolution |
string |
time |
url |
transform-function

示例

更多示例,请参阅我们的使用 CSS 自定义函数指南。

@function 基本用法

此示例展示了一个将传入值加倍的基本函数。

HTML

标记包含一个带有某些文本内容的 <p> 元素:

html
<p>Some content</p>

CSS

在我们的样式中,我们首先定义 CSS 自定义函数。该函数名为 --double,并接受一个任何类型的单个参数,我们称之为 --value。在函数体内,我们包含一个 result 描述符,它使用 calc() 函数将传入的参数加倍:

css
@function --double(--value) {
  result: calc(var(--value) * 2);
}

接下来,我们定义一个值为 10px--base-spacing 自定义属性。我们将该属性赋给 border-radius 值,但随后使用 --double() 自定义函数将其加倍用于 padding 值。

css
p {
  --base-spacing: 10px;
  border-radius: var(--base-spacing);
  padding: --double(var(--base-spacing));
  width: 50%;
  background-color: wheat;
}

结果

规范

规范
CSS 函数与混入模块
# function-rule

浏览器兼容性

另见