css变量无法直接用于mask-image因浏览器不解析var()为有效,@property是chromium唯一支持的动态方案,兼容方案需预设类名并用js切换。

为什么直接用 CSS 变量控制 mask-image 会失败
因为 mask-image 的值必须是合法的 <image></image> 类型,而 CSS 自定义属性(--foo)在运行时无法拼接进 url() 或 linear-gradient() 函数中——浏览器解析器根本不会把 var(--mask-url) 当作一个路径或渐变去处理,结果就是遮罩被忽略,元素全显或全黑。
常见错误现象包括:
-
mask-image: url(var(--mask-url));→ 解析为无效 URL,降级为空遮罩 -
mask-image: linear-gradient(to right, var(--start), var(--end));→ 渐变语法不合法,Firefox/Safari 直接跳过 - 即使 DevTools 显示属性存在,Computed 面板里
mask-image也是none
@property 是唯一可行的运行时动态方案(仅 Chromium)
Chrome/Edge/Opera 支持 @property 声明可动画的自定义属性,配合 mask-composite 和 mask-position 等可动画属性,才能真正实现“动态”遮罩。Firefox 和 Safari 当前(2026 年中)仍不支持 @property 用于 mask 相关动画。
实操要点:
- 必须显式声明
@property,且syntax要匹配目标属性类型,比如控制透明度要用"<number>"</number> - 只能动画那些规范明确标注为「可动画」的
mask子属性:mask-position、mask-size、mask-composite(注意mask-image本身不可动画) - 示例:用
@property控制径向遮罩半径缩放
@property --mask-radius {
syntax: "<length-percentage>";
inherits: false;
initial-value: 0%;
}
.masked {
--mask-radius: 0%;
-webkit-mask-image: radial-gradient(circle at center, #000 0%, transparent 100%);
mask-image: radial-gradient(circle at center, #000 0%, transparent 100%);
-webkit-mask-size: var(--mask-radius) var(--mask-radius);
mask-size: var(--mask-radius) var(--mask-radius);
transition: --mask-radius 0.4s ease;
}
.masked:hover {
--mask-radius: 200%;
}</length-percentage>
更稳妥的「伪动态」方案:预设类 + JS 切换
当需要兼容 Firefox、Safari 或低版本 Chrome 时,放弃运行时生成 mask-image,改用 SCSS 编译期预设 + JS 控制 class 切换。这是目前最稳定、可控性最强的落地方式。
关键设计原则:
- 所有
mask-image值必须是静态字符串,不能含任何插值(#{$var}在url()或gradient()内部必然报错) - 每个遮罩形态对应一个独立 class,如
.mask--fade-left、.mask--circle-clip - JS 只负责增删 class,不操作 style 或插入内联样式
- 用
mask-size: cover+mask-position: center保证响应式适配,避免contain导致留白或裁切异常
iOS/Safari 上遮罩变黑或不生效的硬伤点
这不是代码写错,而是渲染引擎限制:iOS Safari 对 PNG 遮罩图的 alpha 通道极其敏感,哪怕导出时带了色彩配置文件(如 Adobe RGB)、或有半像素抗锯齿残留,都会拒绝解析,表现为整个元素纯黑或全透明。
绕过方法只有两个:
- 用 ImageMagick 剥离元数据:
convert mask.png -strip mask-clean.png - 彻底弃用 PNG,改用 SVG
<mask></mask>引用,例如mask: url(#fadeMask); -webkit-mask: url(#fadeMask);,SVG 不依赖像素精度,只读亮度值,iOS 兼容性远高于位图
别忘了给目标元素加 display: block —— inline 元素在 Safari 中可能因尺寸未计算导致 mask 根本不触发。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











