颜色和角度动画还在靠 JS 算?@property 让浏览器自己会插值了
写过 CSS 动画的人都知道,颜色和数值动画有个共同的坑——插值时颜色跳变、数值动画不平滑。除非你用 JS 或者引入一个动画库,否则浏览器只会做最原始的线性过渡。
CSS @property 这个东西,就是来解决这个问题的。它让你把自定义属性声明成带类型的,浏览器就知道这个值该怎么插值、怎么做动画了。
举一个最直观的例子。
@property --angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.spinner {
--angle: 0deg;
background: conic-gradient(from var(--angle), #ff6b6b, #4ecdc4, #ff6b6b);
animation: rotate 2s linear infinite;
}
@keyframes rotate {
to { --angle: 360deg; }
}
没有 @property 的时候,浏览器不知道 --angle 是什么类型,会把它当成字符串,动画直接失效。加了 @property 声明之后,浏览器知道这是一个角度值,就会正确做 0deg → 360deg 的插值动画。
这个例子的实际效果就是,一个纯 CSS 的 conic-gradient 旋转动画,不需要 JS、不需要 SVG、不需要任何外部库。
颜色也是同理。
@property --primary-hue {
syntax: '<number>';
inherits: false;
initial-value: 200;
}
.button {
--primary-hue: 200;
background: hsl(var(--primary-hue), 80%, 50%);
transition: --primary-hue 0.3s ease;
}
.button:hover {
--primary-hue: 340;
}
hover 上去的时候背景色会平滑地从蓝色过渡到红色,中间的所有中间色浏览器都会帮你算出来。没有 @property,这个过渡会变成跳跃式的。
除了角度和颜色,数字类也适用,特别是做步进动画的时候。
@property --progress {
syntax: '<number>';
inherits: false;
initial-value: 0;
percent: 50;
}
.progress-bar {
--progress: 0;
width: calc(var(--progress) * 100%);
transition: --progress 1s ease-out;
}
.loaded .progress-bar {
--progress: 1;
}
配合 transition 使用,数字从 0 到 1 的过渡配合 calc() 就能驱动进度条宽度,而且浏览器会在每一帧正确插值,不会有任何跳变。
目前 @property 支持的类型有:<number>、<length>、<angle>、<time>、<resolution>、<percentage>,以及由这些类型组合成的 <color>。
你不需要记这么多,用的时候查一下 MDN 就好。关键是理解这个思路:给浏览器一个类型提示,它就能做正确的事。
兼容性方面,Chrome 85+、Edge 85+、Firefox 128+、Safari 16.4+ 已经支持。如果你的项目需要兼容旧版浏览器,可以加个 @supports 检测:
@supports (background: paint(something)) {
/* @property 在这里可用 */
}
如果你的项目里还在用 JS 动画库来处理颜色渐变或者角度旋转,可以先看看 @property 能不能替代。多数简单场景下,一行 @property 声明加一行 CSS 变量就能搞定,不用再引入几十 KB 的依赖。
下一步建议:找一个你现在项目里用 JS 处理的动画,看看它处理的是数值、颜色还是角度,试着用 @property 替代掉。这是成本最低的迁移方式。
评论区
登录后可评论。