使用 CSS 自定义函数
CSS 自定义函数使你能够创建可重用的 CSS 代码块,这些代码块可以接受参数,包含复杂的逻辑(使用 CSS if()
函数和 @media
@规则等特性定义),并根据该逻辑返回值。它们的工作方式类似于 CSS 自定义属性,但提供了更大的灵活性。
在本文中,我们将向你展示如何使用它们,并提供一些实际的例子。
函数基础
一个基本的 CSS 自定义函数定义如下所示:
@function --half-opacity() {
result: 0.5;
}
在 @function
语法之后,我们为函数定义一个名称:--half-opacity
。这必须是一个 <dashed-ident>
类型——它必须以双破折号开头,并且区分大小写。函数名后紧跟一对圆括号(()
)和一对花括号({}
)。
注意:如果多个 CSS 函数被赋予相同的名称,则在级联中更强的 @layer
中的函数会获胜。如果它们都在同一层中,则源代码中最后定义的函数会获胜。
花括号内是函数的主体,这里定义了函数的逻辑。这可以包含多个声明,包括自定义属性(其作用域将限于函数主体)、诸如 @media
之类的 @规则,以及 result
描述符。result
描述符的值被计算以确定函数返回的值。
在这里,我们将 result
设置为值 0.5
:--half-opacity()
函数将始终返回 0.5
。
为什么是“result”而不是“return”?
result
描述符在功能上听起来类似于 JavaScript 函数的 return
语句。然而,CSS 函数中不使用 return
。这是因为,与 JavaScript 的 return
语句不同,CSS 函数不会在遇到 result
声明时立即返回值。
CSS 函数的主体从头到尾进行计算。如果主体中包含多个 result
声明,则源代码中最后一个会覆盖前面的。
调用 CSS 函数
可以使用 <dashed-function>
语法在任何合适的属性值位置调用 CSS 函数,该语法由函数名后跟一对圆括号组成,圆括号内包含要传递给函数的参数(如果有)。例如,我们可以像这样调用我们的 --half-opacity()
函数:
h2 {
opacity: --half-opacity();
}
由于此函数始终返回值 0.5
,因此前面的声明等同于 opacity: 0.5
。这并不是很有用。你还不如直接使用自定义属性或字面量值 0.5
。
让我们继续看看如何使用 CSS 函数。
CSS 函数的特性检测
CSS 函数在没有参数时的一个实际用途是特性检测。在本文我们将要看到的所有示例中,我们定义了一个 --supports()
函数,它看起来像这样:
@function --supports() {
result: none;
}
然后,你可以定义一个“功能不支持”的横幅,并将其 display
属性设置为 --supports()
:
<p class="support">
⚠️ Your browser doesn't currently support CSS custom functions.
</p>
.support {
/* ... */
display: --supports();
}
在支持自定义函数的浏览器中,display
将被设置为 none
,支持横幅将被隐藏。在不支持的浏览器中,display: --supports()
声明将是无效的,因此会被忽略;因此,横幅将被显示。
指定函数参数
CSS 函数参数在函数名后的圆括号内指定为逗号分隔的自定义属性。例如:
@function --transparent(--color, --alpha) {
result: oklch(from var(--color) l c h / var(--alpha));
}
该函数名为 --transparent
,并接受两个自定义属性作为参数,--color
和 --alpha
,它们可以在函数主体内部局部使用。主体包含一个 result
描述符,它使用 CSS 相对颜色语法将输入的 --color
值转换为一个 oklch()
颜色,其 alpha 通道值由输入的 --alpha
值指定。
然后,你可以在任何想要生成现有颜色半透明版本的地方调用此函数。
例如
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color), 0.8);
}
指定数据类型
可以为函数参数和返回值指定允许的数据类型。当你不指定这些时,函数将接受任何类型的值。
让我们修改我们之前的函数以提供数据类型:
@function --transparent(--color type(<color>), --alpha type(<number>)) returns
type(<color>) {
result: oklch(from var(--color) l c h / var(--alpha));
}
每个参数的数据类型在参数名后指定,而 result
的数据类型在左花括号前指定,并以 returns
关键字开头。type()
函数用于指定数据类型。
请注意,在只指定单个数据类型的情况下,可以省略 type()
语法,直接将类型写成简写形式:
@function --transparent(--color <color>, --alpha <number>) returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
现在,只有当输入参数分别为 <color>
和 <number>
,并且 result
是一个 <color>
时,该函数才会产生有效值。否则,例如:
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color), 50%);
}
那么该值将在计算值时变得无效(因为 50%
不是 <number>
而是 <percentage>
),background-color
最终将被设置为 transparent
。
指定多个允许的类型
你可以使用 |
符号作为分隔符来指定多个可接受的数据类型,例如:
@function --transparent(--color <color>, --alpha type(<number> | <percentage>))
returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
在这种情况下,必须使用完整的 type()
语法。
经过这个调整,--transparent(var(--base-color), 50%)
函数调用现在是有效的。
指定默认值
你还可以在参数定义的末尾,用冒号指定参数的默认值。例如:
@function --transparent(--color <color>, --alpha <number>: 0.8) returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
--alpha
参数的默认值现在是 0.8
。如果你想使用这个值,可以在调用函数时省略第二个参数:
section {
--base-color: #faa6ff;
background-color: --transparent(var(--base-color));
}
注意:如果一个无效的值作为函数参数传入,并且该参数定义中指定了默认值,那么无效值将被忽略,而使用默认值。
颜色调整函数示例
你可以在我们的 color-adjust-functions 示例中看到 --transparent()
函数的实际效果(参见源代码)。
这个例子还包括名为 --lighter()
和 --darker()
的函数,它们的工作方式与 --transparent()
类似,但分别返回颜色的更亮和更暗的变体:
@function --transparent(--color <color>, --alpha <number>: 0.8) returns <color> {
result: oklch(from var(--color) l c h / var(--alpha));
}
@function --lighter(--color <color>, --lightness-adjust <number>: 0.2) returns
<color> {
result: oklch(from var(--color) calc(l + var(--lightness-adjust)) c h);
}
@function --darker(--color <color>, --lightness-adjust <number>: 0.2) returns
<color> {
result: oklch(from var(--color) calc(l - var(--lightness-adjust)) c h);
}
像这样的函数库对于基于单一颜色定义颜色方案非常有用:
:root {
--base-color: #faa6ff;
}
section {
background-color: --transparent(var(--base-color));
border: 3px solid --lighter(var(--base-color), 0.1);
color: --darker(var(--base-color), 0.55);
}
包含复杂逻辑
你可以使用诸如 @media
@规则和 if()
函数之类的构造在函数中包含更复杂的逻辑。
我们的 responsive-narrow-wide 示例(参见源代码)展示了一个名为 --narrow-wide()
的函数,它可以为任何属性提供两个值选项。一个在视口低于特定断点时设置,另一个在视口高于该断点时设置。
--narrow-wide()
函数接受两个参数,--narrow
和 --wide
。返回的 result
是 --wide
属性,除非视口宽度小于 700px
,在这种情况下返回 --narrow
。
@function --narrow-wide(--narrow, --wide) {
result: var(--wide);
@media (width < 700px) {
result: var(--narrow);
}
}
该函数可用于在多种上下文中提供响应式的值选项:
body {
display: grid;
grid-template-columns: repeat(--narrow-wide(1, 3), 1fr);
gap: --narrow-wide(0, 20px);
padding: 0 20px;
}
h2 {
font-size: --narrow-wide(2.5rem, 2rem);
}
p {
font-size: --narrow-wide(1.4rem, 1rem);
line-height: 1.5;
}
使用 if()
函数
我们可以使用 if()
函数来重写 --narrow-wide()
函数:
@function --narrow-wide(--narrow, --wide) {
result: if(media(width < 700px): var(--narrow) ; else: var(--wide));
}
一次编写复杂语法,然后重用
CSS 函数的一个关键用例是定义一次复杂的语法片段,然后能够通过更简单的函数调用多次重用它。
我们的 gradient-function 示例(参见源代码)提供了这方面的一个例子。它有一个名为 --shippo-pattern()
的函数,该函数接受长度和颜色参数,并返回一个复杂的 background
值,该值包含多个 radial-gradient()
背景:
@function --shippo-pattern(--size <length>, --tint <color>) {
result:
radial-gradient(closest-side, transparent 98%, rgb(0 0 0 / 0.3) 99%) 0 0 /
var(--size) var(--size),
radial-gradient(closest-side, transparent 98%, rgb(0 0 0 / 0.3) 99%)
calc(var(--size) / 2) calc(var(--size) / 2) / var(--size) var(--size)
var(--tint);
}
定义了这个函数后,我们现在可以创建具有不同色调和圆圈大小的该背景值的变体:
#one {
background: --shippo-pattern(100px, #def);
}
#two {
background: --shippo-pattern(3.5rem, lime);
}
#three {
background: --shippo-pattern(10vw, purple);
}
另见
- CSS 自定义属性
- CSS 自定义函数与混入模块
- Custom CSS Functions in the Browser 作者:Miriam Suzanne (2025)
- CSS @function + CSS if() 作者:Bramus (2025)
- 5 Useful CSS functions using the new @function rule 作者:Una Kravets (2025)