CSS @property 的妙用:把数字动画变得跟绸缎一样顺滑

2026-08-29 0 567

你可能见过这种效果:数字从 0 滚到 100,看起来真带劲。以前用 JS 写,或者靠 requestAnimationFrame 硬算。但今天我想试试 CSS 的新功能 —— @property。你可能听说过这个词,但八成没真正把它用在正经地方。我来演示一个纯 CSS 的数字动画,顺便把渐变过渡也搞顺滑。

先说说这个@property到底是个啥

按官方说法,它就是让你自己定义 CSS 自定义属性的类型、初始值、继承方式。用大白话说:以前 CSS 变量就是个筐,啥都能装,但浏览器不知道它是数字、颜色还是长度。现在你用 @property 告诉浏览器:“这个变量是数字,可参与过渡和动画。”然后浏览器就能对你的变量做插值计算了。

没有它之前,你想让 CSS 变量动起来,基本没戏。因为变量是字符串,浏览器不会自己算 10 到 20 的中间值。现在你说它是 <number>,好,那你给它从 10 变到 20,它就会自动计算中间的 10.5、11.8 这些值。这就是它最大的魔法。

最简单的例子:数字滚动器

我搞一个计数器,从 0 滚到 100,不用 JS,只用 CSS 动画。

@property --num {
    syntax: "<integer>";
    initial-value: 0;
    inherits: false;
}

.counter {
    counter-reset: num var(--num);
    animation: count 3s ease-out forwards;
}

.counter::after {
    content: counter(num);
}

@keyframes count {
    to {
        --num: 100;
    }
}
    

等等,这怎么没看到数字变?因为 counter-resetcounter() 必须配合伪元素。但这里有一个坑:counter-reset 里的 var(--num),在动画过程中到底能不能实时变化?说实话,目前浏览器对这个的支持还是有点微妙。我测试的时候,Chrome 下没问题,但 Firefox 有点一言难尽。如果你只是想要一个平滑的数字动画,直接用 @property 配合 attr() 或者普通元素的 textContent 可能更可靠。

那换个更靠谱的思路:用 <number> 类型,然后把它赋给一个元素的 transformopacity。这能实现真正的平滑插值。

让渐变背景动起来

以前要实现背景渐变的滚动,你只能欺骗自己:用背景位置变化或者双层渐变。但有了 @property,你可以直接注册一个 <color> 类型的变量,然后让颜色本身在两种颜色之间渐变。看这个:

@property --color-1 {
    syntax: "<color>";
    initial-value: #ff6b6b;
    inherits: false;
}

@property --color-2 {
    syntax: "<color>";
    initial-value: #4ecdc4;
    inherits: true;
}

.gradient-box {
    background: linear-gradient(90deg, var(--color-1), var(--color-2));
    transition: --color-1 1s, --color-2 1s;
}

.gradient-box:hover {
    --color-1: #f9ca24;
    --color-2: #6ab04c;
}
    

你在浏览器里试一下,鼠标悬停上去,颜色不是瞬间切换,而是平滑地从红变成黄,从蓝绿变成绿。这感觉很棒,但以前你要用 JS 去搞,或者用伪元素做透明过渡。现在直接定义变量过渡即可。

真正的实战:进度条圆环动画

圆环进度条是常见需求。以前用 SVG 的 stroke-dasharray 过渡,或者 Canvas。现在用 @property 配合 angular-gradient 可以搞出酷炫效果。

@property --angle {
    syntax: "<angle>";
    initial-value: 0deg;
    inherits: false;
}

.circle {
    width: 120px;
    height: 120px;
    border-radius: 50%;
    background: conic-gradient(
        from var(--angle),
        #16a085 0%,
        #16a085 var(--percent, 50%),
        #eee var(--percent, 50%),
        #eee 100%
    );
    transition: --angle 0.3s ease, --percent 0.3s ease;
    /* 简化:把 --percent 也注册下 */
}

@property --percent {
    syntax: "<percentage>";
    initial-value: 0%;
    inherits: false;
}
    

这样你只需要在 JS 里改 --percent 的值,动画就会自动转。但这里的问题是 conic-gradient 中的 from var(--angle),这个角度动画是不是能实时驱动?在我测试中发现 Chrome 可以,但需要配合注册 --angle<angle> 类型。

顺便说一句,@property 还可以用来做卡片翻转、数字跳动、进度条,等等。关键是你得先“注册”变量,告诉浏览器这个变量的类型。

使用注意和兼容性

目前 Chrome、Edge、Opera 都支持 @property,Safari 在 16.4 左右也支持了。Firefox 迟迟没动静,但近期已经在 flags 里出现了。如果你要用于生产,记得用 @supports (property: 1)?其实没有这个判断语法。你可以用 JS 检查是否支持 CSS.registerProperty,那个更靠谱。

还有一点,@property 必须写在 CSS 的顶层,不能在选择器里面,也不能嵌套在 media 里。它是全局定义。

注册的时候,inherits 必须显式指定,不然语法错误。别偷懒。

如果你设置 initial-value 的类型和 syntax 不匹配,对不起,整个规则会无效。

小技巧:让多个变量一起动

比如你做一个卡片,想让它看起来有“呼吸”效果。你注册一个 --scale 的 number 类型,然后在动画里从 1 变到 1.02。或者你把它用在文字阴影上,通过改变阴影距离模拟漂浮,效果很微妙。

@property --float-y {
    syntax: "<length>";
    initial-value: 0px;
    inherits: false;
}

.float-element {
    transform: translateY(var(--float-y));
    animation: float 3s ease-in-out infinite alternate;
}

@keyframes float {
    from {
        --float-y: 0px;
    }
    to {
        --float-y: -12px;
    }
}
    

因为在 @keyframes 里,--float-y 被注册成了长度类型,浏览器会插入每一帧的中间值,你的元素就像被弹簧拽着一样上下浮动,丝般顺滑。

说实话,这玩意也有鸡肋的地方

你不能注册一个对象或数组类型,只能定义基础类型。而且 CSS 动画中如果变量在多个地方使用,性能不一定好,你得自己控制不要滥用。不过对于数字、颜色、角度、长度这些常见类型,它已经非常实用了。

另外,有些时候你用 transition@property 配合,但遇到 display:none 切换或者元素初次渲染,可能不会出现过渡效果。解决办法是给元素加一个小的 animation 触发器。

你可能想问:那我是不是可以扔掉 JS 动画库了?

别做梦。复杂的时间线、缓动控制还是交给 JS 好。但如果你只是需要一个简单的数字变化、颜色渐变、旋转动画,CSS 完全够了。而且让 UI 层面的东西更接近“声明式”,代码可读性还高,调试也不麻烦。

拿我上面那个圆环进度条来说,你只要在控制台里跑一下 element.style.setProperty('--percent', '75%'),圆环就自己转过去了。这不比手写 raf 香?

最终的案例:一个正经的仪表盘计数

我做一个百分比显示器,圆形,中间显示数字,外圈是 conic-gradient 进度。数字部分用 counter 可能有点毛病,那我就直接用 --num 变量的数值来渲染?但 CSS 不能直接显示变量。所以用伪元素的 content 配合 counter,你只需要在 JS 里设置 --num 的整数值,然后 circle 的颜色随之变化。

@哟?
    

不行,还是上完整代码。简单的 HTML:

<div class="meter" style="--num: 30"></div>
    

CSS 里:

@property --num {
    syntax: "<integer>";
    initial-value: 0;
    inherits: false;
}
.meter {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: conic-gradient(#16a085 calc(var(--num) * 1%), #eee 0%);
    transition: --num 0.5s cubic-bezier(0.26, 0.54, 0.32, 1);
}
.meter::after {
    content: counter(num);
    display: block;
    text-align: center;
    line-height: 100px;
    font-size: 24px;
    counter-reset: num var(--num);
}
    

但是 counter-reset 无法接受 calc?其实可以。不过动画时 counter-reset 未必能插值。在这个场景下,数字的变化可能不会很平滑,但环的过渡是平滑的。你要是想让数字也顺利滚动,还得去让 --num 作为整数变化,浏览器可以插值吗?syntax: "<integer>" 支持离散插值步骤,并不是平滑的小数。但如果你的数字变化很快,比如 1 秒内从 0 到 100,它其实是一步一步跳着走的,但人眼看起来接近平滑。想要真平滑,可以注册为 <number>,然后使用 round() 函数或者借助 --display-num 这种 hack。

有点复杂,不过基本思路有了。

最后,别把 @property 想得太神奇

它就是让你能告诉浏览器“这个自定义属性是某种类型”,仅此而已。但它确实打开了 CSS 动画的新大门。那些以前需要借助 JS 才能做的过渡,现在可以完全用 CSS 搞定。试想一下,如果你要做一个主题切换,颜色变量本来在 :root 里,你给它加上 @property 注册成颜色类型,然后过渡时间给上 0.3 秒,那换主题的时候,颜色就像渐隐渐显一样过渡,而不是瞬间切换。这不是很爽吗?

所以你可以试着把项目里的颜色变量、间距变量都注册上类型,然后放心大胆地加 transition。也许那些一直被你吐槽“硬切”的交互,一下子就丝滑起来了。好了,CSS 的魔法就到这,动手去试试吧。

CSS @property 的妙用:把数字动画变得跟绸缎一样顺滑
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请发送邮件1506151422@qq.com联系,将会及时下架删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 css CSS @property 的妙用:把数字动画变得跟绸缎一样顺滑 https://www.taomawang.com/web/css/2664.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务