css变量不能直接插入linear-gradient()参数中,浏览器会丢弃未解析的var()导致遮罩失效;正确做法是将整个渐变声明存为变量(如--mask-grad: linear-gradient(...)),再用mask-image: var(--mask-grad)引用。

mask-image 用 CSS 变量时,linear-gradient() 里的数值为什么不生效?
因为 mask-image 的值本身是图像函数(如 linear-gradient()),而 CSS 变量不能直接插入到函数参数中——浏览器会把未解析的 var(--x) 当作无效值丢弃,最终 fallback 到默认遮罩或完全失效。
常见错误写法:mask-image: linear-gradient(90deg, #000 var(--start), #000 var(--end));
这行在绝大多数浏览器里等价于没写 mask-image,遮罩直接消失。
- 正确做法是把整个
linear-gradient()字符串拼成一个变量,例如--mask-grad: linear-gradient(90deg, #000 20%, #000 80%);,再在mask-image中引用:mask-image: var(--mask-grad); - 变量必须定义在 :root 或目标元素上,且确保作用域覆盖;
calc()不能嵌套在 gradient 参数里,但可以提前算好值再塞进变量 - Chrome 115+ / Safari 16.4+ 支持变量内联计算,Firefox 仍不支持
var()在 gradient 函数中的动态解析
如何用 CSS 变量 + background-position 模拟 mask-position 动画?
直接对 mask-position 加 transition 或 @keyframes 基本无效——旧规范把它标为 non-animatable,直到 2023 年才改,但实现严重滞后。Firefox 至今不支持。
绕过方式是:不用 mask-position,改用 mask-image: linear-gradient() 配合同构的 background-image,把位移控制权交给 background-position(它天然支持动画)。
- 结构上,让遮罩层和背景层使用相同的渐变形状、尺寸和方向,仅通过
background-position错开视觉位置 - 示例:
--mask-x: -50%;→mask-image: linear-gradient(90deg, #000, #000); background-position: var(--mask-x) center; - 然后对
background-position做 transition 或 animation,视觉上就是遮罩在滑动 - 注意:必须设
mask-repeat: no-repeat; mask-size: 100% 100%;,否则位移会被重复或缩放干扰
clip-path 和 mask-image 同时用变量时,哪个更适合响应式动态裁剪?
clip-path: polygon() 支持用 CSS 变量传入坐标点(如 clip-path: polygon(var(--p1), var(--p2), var(--p3));),但只在 Chrome 120+ / Safari 17+ 中稳定;Firefox 对变量坐标的解析仍偶发失败。
相比之下,mask-image 配合 radial-gradient() 或 conic-gradient() 更适合做「软边」动态遮罩(比如呼吸灯、聚焦光斑),因为它能自然过渡,且变量只需控制半径、角度、偏移量等标量参数。
- 需要硬边几何裁剪(如菱形、星形切换)→ 优先试
clip-path+ 变量,但必须加降级:clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);作为 fallback - 需要柔边、渐变、纹理感遮罩 → 用
mask-image+linear-gradient()或 SVG data URL 变量,兼容性更好,动画更稳 - 移动端真机测试重点:iOS 微信 WebView 对
clip-path变量的支持比桌面 Safari 差一到两个版本,务必实测
伪元素遮罩层里用 CSS 变量控制 mask-image,为什么 fixed 定位下会错位?
因为 position: fixed 的伪元素,其 mask-image 的坐标系默认以视口为原点,而变量计算出的 background-position 或渐变偏移量,往往基于父容器尺寸(比如 100vw)。两者基准不一致,就会出现“看起来动了,但没对准”的错位。
最稳妥的解法是统一坐标系:把伪元素设为 position: absolute,父容器加 position: relative,再用 inset: 0(或 top: 0; right: 0; bottom: 0; left: 0; 兼容旧 Safari)铺满。
- 如果必须用
fixed(比如全屏弹窗遮罩),就别依赖vw/vh类变量,改用calc(50% - var(--offset))这类相对父容器的表达式,并确保父容器有明确宽高 - 避免在
::before上同时用mask-image和backdrop-filter—— Safari ≤15 会触发渲染 bug,遮罩区域变黑或闪烁 - 调试技巧:临时加
outline: 1px solid red;到伪元素,确认它的实际绘制范围是否和预期 mask 区域重合
真正难的不是写对变量名,而是变量背后的坐标系、浏览器解析顺序、以及 fallback 是否真能兜住——这些细节在开发机上看不出问题,一上真机就露馅。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











