在做小程序或 H5 时,经常遇到这种需求:
同一套图标,在不同场景要显示成白色、品牌色、灰色......
常见做法有:导出多套 PNG、用 iconfont、filter 染色,或者本文要说的------mask + background-color。
它看起来像「改了图片颜色」,本质其实是:用图片当镂空模板,颜色来自背景色。
1. 一句话描述
Mask 管形状,background-color 管颜色。
mask/mask-image:决定「哪里看得见」background-color:决定「看得见的地方是什么颜色」
图片里原来的 fill / 色值,不会作为最终显示色。
2. 最小可运行示例
html
<view class="icon"></view>
css
.icon {
width: 32px;
height: 32px;
background-color: #1a4d85; /* 最终看到的颜色 */
-webkit-mask: url('/static/icons/question.svg') no-repeat center / contain;
mask: url('/static/icons/question.svg') no-repeat center / contain;
}
效果:页面上出现一个「问号形状」的深蓝图标。
换颜色?只改一行:
css
.icon {
background-color: #fff; /* 白 */
/* 或 #999 / red / currentColor ... */
}
同一张 SVG/PNG,可以设置为任意单色。
3. Mask 属性的作用
可以把元素想成一块纯色木板,把图标 SVG/PNG 想成一张剪纸:
- 先铺一层
background-color - 再用图标当「模板」盖上去
- 模板有图形的地方:背景色透出来
- 模板透明的地方:背景色被裁掉
所以:
| 你以为的 | 实际发生的 |
|---|---|
| 在给图片重新上色 | 在给「背景色」按图片形状开窗 |
SVG 的 #245DEE 会显示出来 |
通常不会;它只影响遮罩轮廓 |
| 不写 background 也能显示原色 | 不会;没可裁切的内容时,往往什么都看不见 |
这也解释了:为什么图标最好是实心剪影(有形状、其余透明)。复杂的彩色插画并不适合当单色 mask。
4. 为什么要同时写 -webkit-mask 和 mask
css
-webkit-mask: url(...) no-repeat center / contain;
mask: url(...) no-repeat center / contain;
| 写法 | 主要覆盖 |
|---|---|
-webkit-mask |
Safari、iOS WebView、多数微信小程序真机环境、Chromium 系 |
mask |
标准属性:Firefox,以及较新的浏览器 |
小程序 / iOS 场景里,-webkit-mask 往往更关键;两边都写是兼容写法:谁认谁生效。
博客里也常见拆开写:
mask-image+-webkit-mask-image。简写
mask/-webkit-mask可以一次带上no-repeat center / contain,更省事。
5. 如果不设置 background-color 会怎样?
不会自动变成 SVG 自带的颜色。
- 有
background-color→ 按遮罩形状露出该颜色 - 没有背景(也没有别的可见内容)→ 裁切的是「空」,图标通常不可见
如果目标就是「原样显示图片颜色」,请直接用 <image> / <img>,别用 mask。
6. 和 filter: drop-shadow 染色对比
另一种常见「单色图标」套路是:
css
.icon-wrap {
overflow: hidden;
color: #fff;
}
.icon-wrap image {
transform: translateY(-32rpx);
filter: drop-shadow(0 32rpx 0 currentColor);
}
思路是:藏起原图,用投影「伪造」一个有色图标。
| 方案 | 优点 | 注意点 |
|---|---|---|
| mask + background | 语义清晰;换色只改颜色值;真机兼容相对稳 | 图标需是剪影;依赖 mask 支持 |
| drop-shadow 投影 | 老项目里常见 | 依赖 filter;原图被藏起,一旦 filter 失效就「彻底空白」;SVG 缺 fill 时真机可能无投影源 |
两者目标类似,但 mask 更接近「换色」本身,也少踩「影子画不出来」这类坑。
7. 实际使用场景建议(可直接当 checklist)
- 图标资源:优先单色剪影 SVG/PNG,透明底
- 尺寸:给容器写死宽高(小程序里尤其重要)
- 颜色 :用
background-color或currentColor(方便跟文字色联动) - 兼容 :
-webkit-mask与mask成对写 - 定位 :
no-repeat center / contain,避免裁切变形 - 别指望 mask 还原多彩色原图------它擅长的是单色图标系统
进阶一点可以用渐变背景,做出双色/渐变图标:
css
.icon {
background: linear-gradient(135deg, #4e6ef2, #8b5cf6);
-webkit-mask: url('/static/icons/star.svg') no-repeat center / contain;
mask: url('/static/icons/star.svg') no-repeat center / contain;
}
8. 一句话总结
mask 不是「给图片调色板」,而是:
借图标的形状,给背景色打孔。
所以博客里说的「通过修改 background-color 得到各种颜色的图案」,完全成立------前提是你接受:最终色来自背景,形状来自图片。
参考
- CSS Mask 相关实践(掘金原文思路)
- MDN: mask / mask-image