这个 CSS 功能简直像 JavaScript:但它 100% 是原生支持的
我研究 CSS 已经很多年了,一直在不断调整样式表,追求那种既简洁又充满动态感的完美平衡。
你是不是也有过这样的经历?写着重复的 CSS 规则,和各种 JavaScript 变通方案纠缠不清,同时心里默默希望自己的设计系统不要变得一团糟。
今天,我们要探讨一个简单的 CSS 功能,它不仅能让你的样式表变得整洁,还能极大提升复用性。
写出简洁又可复用的 CSS
最近我了解到 Chrome 139 推出的新功能:@function 规则,必须告诉你,它真的很酷,也非常惊艳。
这不仅仅是一个普通的 CSS 新特性,它是一种更聪明、更可复用的样式编写方式,感觉就像是专门为 2025 年准备的。
接下来,我们就来看看 @function 是如何让你的设计系统变得更简单,从流体排版到主题切换,所有代码你今天就能直接用到项目里。
什么是 @function 规则?
@function 规则允许你定义自定义的 CSS 函数,用来封装可复用的样式逻辑。你可以把它想象成一个迷你 JavaScript 函数,只不过它是专为 CSS 设计的:纯粹、声明式,并且直接内置于浏览器中。
为什么这对你有意义?
因为它能帮你减少重复代码,让你的样式表在不依赖预处理器或脚本的情况下,也能具备动态能力。
先来看一个简单的例子:
@function --dashed-border(--color: red) {
result: 2px dashed var(--color);
}
这就创建了一个可复用的自定义边框样式函数。很酷的一点是,我们还可以为它设置默认值,比如上面例子中,我们把默认颜色设为红色。
使用方式如下:
div {
border: --dashed-border(blue);
}
一种简单快捷的编写可复用 CSS 代码的方法。看起来是不是很清爽?
实战案例 1:轻松实现负值
有时候我们需要为 margin 或定位设置负值,但用 calc() 很快就会变得混乱不堪。
一个自定义的 @function 能让它保持整洁和可复用。
@function --negate(--value) {
result: calc(-1 * var(--value));
}
.navigation {
margin: --negate(30px);
}
这样就能把任意数值转换为其相反数,非常适合动态布局。再也不用手动写一堆 calc() 了。是不是很巧妙?
实战案例 2:让透明度设置更简单
以前,像 hover 或 disabled 状态下的颜色透明度调整,往往意味着要写重复的规则,或者动用 JavaScript。
有了 @function,你可以把这套逻辑封装在一处。
@function --opacity(--opacity, --color: #007bff) {
result: rgb(from var(--color) r g b / var(--opacity));
}
button {
background: --opacity(0.8);
}
button:hover {
background: --opacity(1);
}
button:disabled {
background: --opacity(0.3, gray);
}
再配合一个与主题或状态绑定的自定义属性,你就能实现动态按钮样式,而无需增加额外的类名。我们同样为它设置了默认颜色。
实战案例 3:流畅的响应式字体排版
流体排版(fluid typography)是响应式设计的必备技能,但反复写 clamp() 实在是痛苦。
一个 @function 就能让它变成一行代码。
@function --fluid-type(--font-min, --font-max, --type: 'header') {
--scalar: if(style(--type: 'header'): 4vw; style(--type: 'copy'): 0.5vw);
result: clamp(var(--font-min), var(--scalar) + var(--font-min), var(--font-max));
}
h1 {
font-size: --fluid-type(24px, 36px);
}
p {
font-size: --fluid-type(16px, 24px, 'copy');
}
这样,字体会根据视口大小平滑缩放,还能为标题或正文设置不同的缩放规则。
你试过不用函数来实现这个效果吗?那简直是噩梦 。
实战案例 4:自适应布局的条件圆角
当元素靠近视口边缘时去掉圆角,可以避免布局显得突兀,但用媒体查询就太重了。
一个 @function 能优雅地解决这个问题。
@function --conditional-radius(--radius, --edge-dist: 4px) {
result: clamp(0px, ((100vw - var(--edge-dist)) - 100%) * 1e5, var(--radius));
}
.box {
border-radius: --conditional-radius(1rem);
}
.box-2 {
border-radius: --conditional-radius(1rem, 0px);
}
这样,当元素触碰到视口边缘时,圆角就会自动消失,保持布局整洁。
完全不需要媒体查询。这才是我心目中理想的 CSS。
实战案例 5:无限制的明暗主题切换
light-dark() 函数对颜色主题切换很友好,但边框、字重或尺寸怎么办?
一个自定义的 @function 可以把主题能力扩展到任意属性。
@function --light-dark(--light, --dark) {
result: if(style(--scheme: dark): var(--dark); else: var(--light));
}
:root {
--root-scheme: light;
--scheme: light;
@media (prefers-color-scheme: dark) {
--root-scheme: dark;
--scheme: dark;
}
}
@scope ([data-scheme]) {
:scope {
--scheme-from-attr: attr(data-scheme type());
--scheme: if(style(--scheme-from-attr: system): var(--root-scheme); else: var(--scheme-from-attr));
color-scheme: var(--scheme);
}
}
使用方式如下:
[data-scheme] {
color: light-dark(#333, #e4e4e4);
background-color: light-dark(aliceblue, #333);
border: 4px --light-dark(dashed, dotted) currentcolor;
font-weight: --light-dark(500, 300);
font-size: --light-dark(16px, 18px);
}
<div class="stylable-thing" data-scheme="light">
…
</div>
实战案例 6:响应式侧边栏布局函数
我们再创建一个用于响应式侧边栏布局的工具函数。
@function --layout-sidebar(--sidebar-width: 20ch) {
result: 1fr;
@media (width > 640px) {
result: var(--sidebar-width) auto;
}
}
.layout {
display: grid;
grid-template-columns: --layout-sidebar();
}
这个 @function 为侧边栏和主内容区域设置了一个响应式网格。在小屏幕上,侧边栏占满整行;在大屏幕上,则切换为固定宽度,主内容区域自动填满剩余空间。
额外福利:用 CSS 函数进行类型检查
CSS 的 @function 规则可以对参数和返回值进行类型检查,就像使用 @property 定义的变量那样。这能确保你的函数只接受有效的输入,并产生预期的输出,尤其是在配合内联条件进行动态计算时。
我们来看一下怎么做:
@function --custom-spacing(--a <length>) { }
@function --custom-background(--b <color>) { }
@function --custom-margin(--c <length>+) { }
@function --wideness(--d type(<number> | <percentage>)) { }
我们甚至还能对返回值进行类型约束:
@function --progression(--current, --total) returns <percentage> {
result: calc(var(--current) / var(--total) * 100%);
}
为什么这感觉像是未来
以前我总是依赖 Sass 或 JavaScript 来处理这类逻辑,但现在 @function 把这一切都带进了原生 CSS。
它不仅让你写更少的代码,更让你写出能够智能适应的样式。
而且,它与 React 19 推崇的优化渲染理念不谋而合——更精简的样式表,意味着更快的应用性能。
有什么限制吗?
Chrome 139 是非常前沿的版本,所以目前浏览器支持还很有限。这里没法用 polyfill 来解决,但你可以使用特性检测或为旧浏览器提供降级方案。
.browser-support {
margin: 2rem auto;
width: max-content;
@supports (color: --function(value)) {
display: none;
}
}
这样,在你探索新功能的同时,也能保障应用的兼容与安全。
最后的建议
在你下一个项目中尝试加入一个 @function。可以先从小处着手,比如一个流体尺寸工具函数,或者一个主题切换器。
你最想用 @function 解决的 CSS 痛点是什么?欢迎在评论区分享你的想法。
感谢阅读,我们下次再见,带来更多酷炫的 CSS 小技巧。