可通过@property注册带类型自定义属性实现渐变动画,因浏览器无法对gradient字符串插值,需拆解角度、颜色等为可插值原子属性并用transition作用于变量名本身。

不能直接对 background-image 或渐变函数做 transition,但通过 @property 注册带类型的自定义属性,再把它“注入”到渐变中,就能实现真正平滑的原生动画。
为什么直接 transition 渐变会失败
浏览器把 linear-gradient(0deg, red, blue) 当作一整段字符串,两个不同渐变之间没有数学插值路径。你写 transition: background-image 0.3s,结果只是从 A 字符串硬切到 B 字符串,毫无过渡可言。
- 常见错误现象:hover 时背景色“咔”一下跳变,DevTools 里看到
background-image值瞬间替换 - 根本原因:未注册的自定义属性(如
--start-color)在 CSS 中仍是无类型字符串,transition无法识别其语义 - 验证方式:运行
CSS.supports('property', '--start-color')返回false,说明注册失败或未生效
@property 必须写在 :root 或 @layer 顶层
@property 不是普通样式规则,它是一次性向 CSS 引擎“注册契约”,必须脱离选择器作用域。
- ❌ 错误写法:
.card { @property --hue { syntax: "<number>"; ... } }</number>—— 浏览器直接忽略整条规则 - ✅ 正确位置:
:root、@layer base、或未嵌套的全局 CSS 块(如单独theme.css文件顶部) - 注册后,所有用到
var(--hue)的地方才能参与插值;但变量本身仍需在目标元素上显式赋值(如.card { --hue: 220; })
渐变动画要拆解为多个可插值的原子属性
一个 linear-gradient 包含角度、起始色、终止色等多个维度,浏览器不支持对整个函数插值,所以得把每个可变部分单独注册为带类型的属性。
- 角度动画:
@property --grad-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }</angle> - 颜色动画:
@property --grad-start { syntax: "<color>"; inherits: false; initial-value: #667eea; }</color> - 组合使用:
background: linear-gradient(var(--grad-angle), var(--grad-start), var(--grad-end)); - ⚠️ 注意:
syntax: "<color>"</color>的引号和尖括号是字面量,不能写成"color"或<color></color>;initial-value必须是合法颜色值(#rgb、rgb()、hsl()),不能是currentcolor或未定义变量
transition 必须作用于自定义属性名本身
动画触发点不是最终渲染属性(如 background),而是你注册的那个变量名。
- ✅ 正确:
transition: --grad-start 0.4s ease, --grad-angle 0.4s ease; - ❌ 错误:
transition: background 0.4s;或transition: background-image 0.4s;—— 这些永远无效 - hover 时也必须改变量:
.card:hover { --grad-start: #f5576c; --grad-angle: 90deg; } - 如果用
@keyframes,必须写from { --grad-start: #667eea; }和to { --grad-start: #f5576c; },不能在 keyframe 里直接写background
最容易被忽略的是 @property 的三项描述符缺一不可,且 syntax 和 initial-value 类型必须严格匹配——错一个字符,整条规则静默失效,后续所有动画都退化为跳变。Firefox 目前仍不支持(截至 128 版),线上项目务必加 @supports (property: --x) 回退逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











