必须用 mask-image + 内联 svg ,firefox 不支持 mask 简写和外部 svg;chrome/safari 兼容性差异大,渐变和多层遮罩需用 svg 实现。

直接结论:不要用 mask 简写,必须拆成 mask-image + 显式前缀,且 Firefox 完全不认 -webkit- 前缀;跨浏览器生效的唯一可靠路径是内联 SVG <mask></mask> + url(#id) 引用。
为什么 mask: url(#m) 在 Firefox 里完全没反应
Firefox 从 v53 起就废弃了单值 mask 简写语法,看到它直接跳过、不报错、不 fallback。即使你写了 mask: url(#myMask),computed 面板里 mask-image 仍显示为 none。
- ✅ 正确写法:
mask-image: url(#myMask)(无前缀) - ❌ 错误写法:
mask: url(#myMask)或-moz-mask: url(#myMask)(已移除) - ⚠️ 注意:
url(#myMask)中的#不能省,ID 必须和目标元素在同一个 HTML 文档内(iframe 或 Shadow DOM 会断开)
mask-image: url("mask.svg") 为什么在 Chrome 有效、Firefox 失效
Firefox 对外部 SVG 文件有严格限制:它不支持 mask-image: url("mask.svg") 加载跨域或非同源 SVG,静默失败,元素直接“消失”。Chrome/Safari 则能正常加载。
- ✅ 可靠方案:改用 data URL 内联 SVG,例如:
mask-image: url("data:image/svg+xml,%3Csvg...%3E") - ✅ 更推荐:把
<mask id="m">...</mask>写进页面顶部隐藏的<svg width="0" height="0"></svg>里,再用mask-image: url(#m) - ⚠️ 不要导出 Figma/Sketch 的 SVG 直接用——检查 fill 是否为
#fff,删掉所有opacity和stroke,否则遮罩反向或变淡
Safari 15.4+ 与 Firefox 对渐变遮罩的解析差异
你写 mask-image: linear-gradient(to right, black, transparent),Chrome 可能淡出,Firefox 直接忽略(不支持渐变值),Safari 则把 transparent 当作 #000 导致全黑失效。
- ✅ 统一解法:渐变必须定义在 SVG
<mask></mask>内,用<lineargradient></lineargradient>+stop-color="#000"/stop-color="#fff" - ✅ Safari 要求
maskUnits="userSpaceOnUse"才能正确映射到元素尺寸,否则圆角/缩放错位 - ⚠️ Firefox 默认按
luminance模式读图,rgba(0,0,0,0.5)会被转成灰度值;若要走 alpha 通道,必须加mask-mode: alpha且渐变用rgba()
多层遮罩 + mask-composite 别白费劲
mask-composite: subtract 这类布尔运算,在 Chrome 里写了等于没写(Blink 引擎至今未实现),Firefox 不识别标准语法,Safari 行为不统一。DevTools 显示“已应用” ≠ 实际像素被裁切。
- ✅ 真正落地方案只有两个:
– 改用 SVG 内联<mask></mask>,在<circle mask-composite="subtract"></circle>里写逻辑
– 或彻底降级:只用单层mask-image,接受默认add叠加效果 - ⚠️ 如果硬要用 CSS 多层,
-webkit-mask-composite和mask-composite必须成对出现,且所有配套属性(mask-position、mask-size等)数量严格一致,否则整条声明被截断
最常被忽略的细节是:Safari 中 url(#id) 引用失效时,没有任何提示;你得手动把 <svg></svg> 提到页面可视区,临时加 border 确认它是否被正确解析。兼容性不是靠堆前缀解决的,而是靠绕开浏览器尚未实现的规范分支。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











