这篇文章发布于 2018年11月24日,星期六,20:13,归类于 CSS相关。 阅读 54667 次, 今日 12 次 17 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8187
本文可全文转载,个人网站无需授权,只要保留原作者、出处以及文中链接即可,任何网站均可摘要聚合,商用请联系授权。
一、开始,关于图标变色,引言
上周写了篇文章,利用filter:hue-rotate色调旋转滤镜改变按钮颜色进行复制,后来我就一想,利用滤镜岂不是可以很方便改变小图标的颜色,这样,SVG图标作为背景图使用也没有任何问题了。
其实以前写过一篇文章——“PNG格式小图标的CSS任意颜色赋色技术”,用的是drop-shadow
,优点是可以任意颜色,不足就是有些小啰嗦。
所以,我要研究下,有没有使用简单的的赋色技术;以及研究下有没有滤镜以外的其它技术可以修改小图标颜色!
结果,还真发现了不少好玩的东西。
二、图标变成黑色或白色的技巧
先从简单的说起。
有下面这个图标:
如果要变成纯黑色,或者纯白色,则可以这样:
/* 图标变黑色 */ .black { filter: brightness(0); } /* 图标变白色 */ .white { filter: brightness(100); }
也就是使用亮度滤镜,要想变成黑色,很简单,设置亮度为0即可,保证黑如焦炭;如果想要变成白色,则亮度设成很大很大的值就好了,例如100,保证白如奶昔。
实现后的效果如下截图:
眼见为实,您可以狠狠地点击这里:CSS让图标变成白色或黑色demo
三、图标变色为任意指定颜色
黑白色确实简单,但实际开发时候,往往是黑色图标变成彩色,那可该怎么办呢?
可以实现!
CSS3 filter滤镜有调整色调的hue-rotate,有调整饱和度的saturate滤镜,有调整亮度的brightness滤镜,有调整对比对的contrast滤镜等,把这些滤镜进行组合,进行色值变换,总会得到我们希望的颜色的。
关键如何变呢?
嘿嘿!我花了2晚上时间学习、探索与研究,终于弄出了一个任意色值通过filter滤镜进行转换的在线工具。
您可以狠狠地点击这里:CSS filter滤镜任意色值转换在线工具
使用和转换示意如下GIF:
第一个输入框输入原始的图标颜色,下面输入框输入图片目标颜色,点击“转换”按钮,对应的filter CSS代码就生成了。
注意注意注意
由于部分滤镜渲染并非是线性的,因此最终转化后的颜色并非100%完全一致,可能会出现误差。
请不要担心,再次点击“转换”按钮,尝试其他的滤镜组合①,找到最精确的那个filter代码。
举例说明
例如,原始色是:#000000,目标色非web安全色,是#f4615c。
填入到工具对应输入框,点击“转换”按钮,结果如下:
可以看到色值误差较大,请不要担心,再多点几次“转换”按钮,尽量找到误差值在2以内的色值,如下GIF示意:
虽然最终色值会有偏差(越远离安全色出现偏差概率越大),但对于用户而言,根本没有影响,华为手机边缘蓝光不也照样使用。对于设计师,也完全不要担心,放心使用,他们是根本无法区分屏幕上#f5615c
和设计稿中#f4615c
和的差别的。即使是全球几个罕见4色视觉人也无法区分,毕竟是不同设备的显示器。
同一色值可以有多种滤镜组合呈现的,例如黑色转白色,可以亮度滤镜,也可以直接反相滤镜。每次点击工具页的“转换”按钮,都会会尝试一种匹配。其底层是不同视觉系数的计算值的相互组合,类似计算灰度有下面两种算法:
- sRGB Luma (ITU Rec. 709): L = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255
- W3C方法(工作草案): L = (red * 0.299 + green * 0.587 + blue * 0.114) / 255
三、使用滤镜让图标变彩色实战
还是这个图标:
下面要变成#f4615c色值图标。
原始值是#2486ff,目标值是#f4615c,借助工具,得到如下CSS:
filter: invert(52%) sepia(82%) saturate(2494%) hue-rotate(327deg) brightness(104%) contrast(92%);
结果如下截图:
您可以狠狠地点击这里:CSS filter让图标变成指定红色值demo
四、CSS遮罩实现任意颜色图标
这个是相比上面的滤镜更好的实现方法,性能要比滤镜好,色值定义也更简单。
一例胜千图
还是这个图标:
下面要变成#f4615c色值图标。
如下HTML和CSS代码就好了:
<span class="colorful"></span>
.colorful { display: inline-block; width: 32px; height: 32px; background-color: #f4615c; -webkit-mask: url(./xin.svg) no-repeat; mask: url(./xin.svg) no-repeat; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; }
CSS3 mask默认是基于透明度实现遮罩效果的。也就是实色区域显示,透明区域隐藏。因此,我们只需要把目标图标颜色#f4615c作为背景色,然后原始图标(无论什么颜色都可以)作为遮罩图片,效果就出来了。
眼见为实,您可以狠狠地点击这里:CSS mask遮罩实现任意颜色的小图标demo
效果如下截图:
CSS mask学习
CSS3遮罩非常好用,熟练掌握事半功倍,其知识点很多,包含的属性值也很多,有兴趣可以参考我之前的文章:“CSS遮罩CSS3 mask/masks详细介绍”,非常系统的介绍了相关知识点。
五、新增:借助background-blend-mode混合模式
background-blend-mode
混合模式15年的时候就写文章介绍过,可参见“CSS3混合模式mix-blend-mode/background-blend-mode简介”。
本方法有2个限制,首先原图片必须是纯黑色的,如果是彩色的,颜色会混淆在一起;其次非图形部分必须是白色,不能是透明,因为透明会被当做黑色处理。
换成下面这个黑色白底图标:
下面要变成#f4615c色值图标。
如下HTML和CSS代码就好了:
<span class="colorful"></span>
.colorful { display: inline-block; width: 32px; height: 32px; background-image: url(./xin.png), linear-gradient(#f4615c, #f4615c); background-blend-mode: lighten; background-size: 100%; }
混合模式lighten
可以让任意颜色和黑色混合的时候,保留原始色彩。由于我们图标黑色白底,和任意渐变图片混合,都会在黑色图形区域留下渐变图形的颜色。于是,效果达成!
眼见为实,您可以狠狠地点击这里:CSS混合模式与PNG格式小图标赋色demo
效果如下截图:
更新于2022-01-31
上面的案例代码有问题,需要图标有白色背景才可以,实际上不需要,镂空图标也是支持的,相关代码和案例参见这篇文章:“CSS background背景图标的变色技巧”
六、最后,关于转换工具,结语
正文部分结束,下面可以安心地东扯西扯了。
filter色值转换工具我一开始想得比较天真,颜色值不是可以HSB表示嘛(web中是HSL,PS中是HSB,两者有差别,),不正好对应filter的色调,饱和度和亮度滤镜嘛,我想计算出前后颜色的HSB值,再一比较,设置在filter上,色值不就转换好了。
一番实践下来发现,设计偏差还相当明显,根本不能拿出来用。因为S和B可以大于100%,且没有上限,具体如何渲染并不是一种线性的关系,只通过简单线性计算是很难实现准确的转换的,需要对矩阵比较了解。于是我自己又尝试去研究feColorMatrix的算法,发现自己的积累还不够,数学不是很强,图形领域也未深入,无法驾驭。
后来,在stackoverflow上找到纯filter滤镜转换黑色为其它颜色的问题,其中提供了一些解决方案。
还是得站在巨人的肩膀上,对原算法进行了一些优化,包括支持任意颜色filter转换,原算法是仅黑色;优化了误差的算法,原算法有较大问题,有时候明明视觉差异明显,却显示误差很小;增加了滤镜转换之后的渲染颜色的输出。就这样一个纯filter变色的在线小工具诞生了。
虽然这个filter变色工具很有技术含量,但是,并不表示使用filter是最好的图标变色方法。如果条件允许(有HTML操作权限),我建议优先使用mask遮罩实现任意图标的变色,兼容性更好,性能更好,颜色100%精准,可以在移动端项目中使用,如果对于一些杂牌Android不在意的话。
如果我们的图标是用的<img>
或者<svg>
标签直连的,则此时,使用filter变色要更合适。
没有无用的技术,只是适用场景宽窄有别而已!
SVG图标和PNG图标
如果是SVG图标,更好的变色处理是SVG Sprites技术,直接fill或color属性控制颜色,兼容性直达IE9。
如果是PNG图标,则多半就要考虑使用本文提供的方法了。
好,扯完了。
感谢阅读,欢迎纠错!欢迎交流!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=8187
(本篇完)
- Pixi.js中ColorMatrixFilter自带滤镜效果一览 (0.304)
- FDCon2019大会分享之滤镜与混合模式实录 (0.294)
- 几行CSS让整站支持深色模式的探索与拓展 (0.294)
- 使用纯CSS实现噪点效果 (0.167)
- 全新的CSS相对颜色语法-使用from和calc() (0.166)
- 介绍一种全新的clipPath Sprites小图标技术 (0.147)
- HTML中无标签文本的CSS变色技巧 (0.119)
- SVG图标颜色文字般继承与填充 (0.118)
- 第五届CSS大会主题分享之CSS创意与视觉表现 (0.111)
- 未来必热:SVG Sprites技术介绍 (0.099)
- 告别图片—使用字符实现兼容性的圆角尖角效果beta版 (RANDOM - 0.003)
算出來有時候差很多
颜色转换工具的成功率不太高,基本要点一两百次才能遇到2以下,不知道原理,是否可以讲解下,或者放出来一起优化一下
謝謝您的文章,對於小弟我在網頁上處理圖片顏色的工作有很大的幫助,尤其是那個幫忙尋找適合的濾鏡轉換的工具真的是太方便了~在一次感謝!!!
滤镜转换颜色工具,咋实现的呀,想看看源码
牛的很呀
工具太强了?
brightness(100)变换白色会有问题 有可能会在图片周围糊一圈
用
filter: brightness(0) invert(1);
可以避免出现的坑为啥我的原始色是#1e2c24,目标色是#050318的时候试了几万次误差还是很大。
厉害,多谢~
cool, 原理之前就了解,实际算法实现不容易!
这也太强了吧!马住
优秀
?哥,可以放 GitHub 上吗
可以,保留原作者和出处就行。
色域是个大坑……
(我匠白光今天就是要…!@¥@¥#%…%…@#)
真棒,你把这些玩的好透彻。