PNG格式小图标的CSS任意颜色赋色技术

这篇文章发布于 2016年06月8日,星期三,01:17,归类于 CSS相关。 阅读 165125 次, 今日 14 次 81 条评论

 

补充于2018-11-26
有多个比本文更好的实现方法,请参考这篇文章:“纯CSS实现小图标变色的一些研究”。

一、眼见为实

CSS可以修改图片的颜色,没错,可以,眼见为实!您可以狠狠地点击这里:png小图标CSS赋色demo

上面的不是很黑的是原始图标,是个PNG图片,下面这个是可以赋色的:

可以变色的图标

下面,我们随意选择一个颜色,例如紫色,然后:
紫色赋色

红色赋色

是不是感觉很厉害!以后设计师就不需要在提供几套颜色的图片了。

SVG, icon fonts等技术似乎也不是那么耀眼了。

二、原理其实很简单

原理其实很简单,使用了CSS3滤镜filter中的drop-shadowdrop-shadow滤镜可以给元素或图片非透明区域添加投影。

如果对drop-shadow不是很了解,建议先看看前些时间写的“CSS3 filter:drop-shadow滤镜与box-shadow区别应用”一文!

对于背景透明的png小图标而言,如果我们施加一个不带模糊的投影,不就等同于生成了另外一个颜色的小图标了吗?

然后,我们把原始图标隐藏在容器外面,投影图标在容器中间,不见给人感觉是赋色效果了?

比方说本文的demo,如果把icon父级的的overflow:hidden去掉,原始的图标就暴露出来啦!

去掉overflow:hidden之后

三、实现的时候实际有难度

原理如上面,我一开始实现的时候,以为很简单,因为分分钟可以实现自己的想法,后来发现有些天真了,Chrome浏览器怎么都显示不出来;FireFox浏览器却可以!咦,究竟发生了什么。

在Chrome浏览器下,drop-shadow有一个如下的呈现特性:

在Chrome浏览器下,如果一个元素的主体部分,无论以何种方式,只要在页面中不可见,其drop-shadow是不可见的;实体部分哪怕有1像素可见,则drop-shadow完全可见。

所以,我试过:

  • text-indent负值隐藏原始图,无投影,失败!
  • clip剪裁隐藏,无投影,失败!
  • margin负值隐藏原始图,无投影,失败!
  • left负值隐藏原始图,无投影,失败!

通通不行,实现遇到了巨大的阻碍。

后来,灵光一现,如果我实体部分也在可视区域内,但是是透明的,会怎样呢(反正不会有投影出来)?

于是,我就试了下曾经立下无数战功的透明边框,卧槽,又立功了,成了!

因此,下面这一个CSS声明是千万不能少的:

border-right: 20px solid transparent;

四、关于兼容性

IE13+支持,Chrome和FireFox浏览器支持,移动端iOS支持,Android4.4+支持。也就是,基本上,移动端现在可以使用这种技术了。

既节约了流量,也让我们的开发更简单,维护更方便了。

五、结语碎碎念

其实,本文的技术发明(主要是透明border的处理)在“drop-shadow vs box-shaow”这篇文章完成后就研究出来了。本来想写个小专利,蹭点早饭钱。结果,新厂子写专利没费用,而且周期要3年。

3年我儿子都可以打酱油了。所以,罢了,直接分享出来。

今天8号,本月已经6篇文章了,写文章暴走了下。就是为了腾出大段且连续的业余时间,要秘密进行其他大项目。

时光机
如果你是3~5年之后看到此文,而且你是2016年上大学的,那么,我在写这篇文章的时候,你可能正在翻来覆去睡不着,还在焦虑明天的考试。总之,不要担心,我给大家找了一个非常硬的后台,保证你们这次高考无忧,放心睡觉吧!哟,你在好奇是哪个后台。嘻嘻嘻嘻,说出来怕吓着你————观音菩萨!

(本篇完)

分享到:


发表评论(目前81 条评论)

  1. 搬砖一号说道:

    自己写的直接修改png图片颜色,可以整合成一个标签里

    .icon-color{
    display: inline-block;
    width: 20px;
    height: 20px;
    background: url(../img/delete.png) no-repeat center;
    overflow: hidden;
    &:after{
    content: ”;
    display: block;
    height: 100%;
    transform: translateX(-100%);
    background: inherit;
    filter: drop-shadow(20px 0 0 red);
    }
    }

  2. 果冻王说道:

    border-right: 20px solid transparent; 这个貌似在最新的chrome浏览器下已经不需要了,我试了一下删掉后图标也不会消失了。

    按照文中描述“在Chrome浏览器下,如果一个元素的主体部分,无论以何种方式,只要在页面中不可见,其drop-shadow是不可见的;实体部分哪怕有1像素可见,则drop-shadow完全可见。”,是不是这里border-right-width设置1px就足够让图标显示了。

    • aliang说道:

      貌似新chrome中不需要了,但是移动端还是需要用border-right: 20px solid transparent; 不然用margin 或left -20px;隐藏原始图标都得不到投影

  3. BryanZhang说道:

    张老师还是很高产,阅文上市赚不少啊

  4. wyy说道:

    想问怎么实现hover后只显示改变颜色的图片,原图片隐藏

  5. wyy说道:

    这个方法真心很赞

  6. maclee说道:

    博主您好:
    这个效果好像在Edge浏览器不能呈现,您有什么好的方案解决没?问题好像是 overflow: hidden;属性会遮盖住内部所有多余的元素,还请您调试下

  7. wl22说道:

    这个方法是真牛逼啊

  8. 说道:

    在移动端Android 4.2.2系统和Android 5.1.1系统上都没有效果,我也是使用的border-right:px solid transparent;这改如何是好?

  9. 西瓜说道:

    厉害了

  10. 蔡考拉说道:

    这个demo不严谨,用left负值有些浏览器无法显示,用translateX倒是可以。还有部分手机机型要开启CSS硬件渲染,不然drop-shadow会模糊。透明border倒是神来之笔哈哈

  11. 大坚说道:

    很实用的奇淫巧技!
    “在Chrome浏览器下,如果一个元素的主体部分,无论以何种方式,只要在页面中不可见,其drop-shadow是不可见的”。
    这个提示,实测没问题,
    但是我用了另外一种方式,就没有那么麻烦了!
    transform:translateX(-100%);

    • 冷酷的冰淇淋说道:

      你说的是对的,只需要在png图片所在区域对应的css里加上两行,一个transform,一个filter: drop-shadow(…)就ok了,transform负责移到区域之外,drop-shadow负责给投影上色,再把投影移到原来的位置。楼主的方法过于复杂,应该会有更简练的写法的。

  12. 膜拜一个说道:

    我擦,大神!请务必收下我的膝盖~~~
    想我之前碰到这种问题,一向都只能PS的~~~ヾ(。`Д´。)

  13. sunflower说道:

    可以使用outline 代替border,这样的话icon不会多占据空间,布局会好点

  14. Mask说道:

    大锅,发现你的demo在微信和qq浏览器中无法显示图标,感觉是因为他们都是用的x5内核,然后这个可恶的内核不支持这个好特性,真操蛋啊!
    所以以后大锅你写兼容性的时候还得测测qq浏览器这个鬼~

    • 说道:

      还真是,现在很多手机应用是在微信下的。用icon font微信也可以了。

    • Mescal说道:

      我在微信小程序里也遇到了该问题,你可以试试用translateX代替left,我这边是可以了。

  15. SplendidDream说道:

    谢谢提供的好方法,我自己用伪类来精简一下,html 会少一层嵌套:

    .icon { display: inline-block; width: 20px; height: 20px; overflow: hidden;position:relative; }
    .icon:after {left: 0;top:0;position:absolute; content: ”;display:block;height:20px;width:20px;text-align:center;border-right: 20px solid transparent; background:transparent none no-repeat center center;-webkit-filter: drop-shadow(20px 0 #f00); filter: drop-shadow(20px 0 #f00); }
    .icon-del:after { background-image: url(‘home.png’); }

    已经应用到实际项目了,哈哈。

  16. kimi2353说道:

    测试发现安卓端的微信不支持,希望得到解决方法

  17. carlz说道:

    大神,发现了一个bug,找了一下午。。终于找到解决办法了,但是不是很理解为什么

    在嵌套多层标签,并给 icon 添加了overflow:hidden之后不显示任何东西,完全被隐藏掉。
    给外层添加了z-index属性之后,bug就被修复了,这个是为啥

    • returnTrue说道:

      兄dei。。我也遇到这个bug了,只不过不是不显示,是闪一下

    • colorlemon说道:

      刚好遇到相同问题,发现外层如果有滚动条就会影响渲染,隐藏的部分不会渲染投影,如果有滚动条那个容器添加z-index属性就会修复。

  18. rockyxia说道:

    与SVG, icon fonts等技术相比不能矢量的

  19. ekoo说道:

    这样也可以达到相同的效果:
    .icon {
    display: inline-block;
    width: 20px;
    height: 20px;
    overflow: hidden;
    }
    .icon-del {
    background: url(“http://www.zhangxinxu.com/study/201606/delete.png”) no-repeat left;
    }
    .icon > .icon {
    width: 40px;
    position: relative;
    left: -20px;
    -webkit-filter: drop-shadow(20px 0 red);
    filter: drop-shadow(20px 0 red);
    }

  20. allen3039说道:

    border-right: 20px solid transparent; 神来之笔

  21. HAI说道:

    我在MAC的chrome上发现没有出现图标,hover时出现了两个图标

  22. Cary说道:

    “border-right: 20px solid transparent;” 这个都能想到,真牛,在看了你“CSS3 filter:drop-shadow滤镜与box-shadow区别应用” 这篇文章后,就有这种想法……

  23. 黄思嘉说道:

    微信不支持吗?求解决

  24. MiYogurt说道:

    满满的 hank 黑科技,佩服,跟着鑫旭大哥涨姿势,长见识。

  25. 梅赛德斯说道:

    看了博文收益很多,以后会持续关注,另外和博主一样我也喜欢钓鱼,博主好像是传统钓啊?最近没有钓鱼吗?

  26. Asiaidc.net说道:

    喜欢看鑫大虾的 碎碎念部分,简直就是临结尾了还要再次高潮经典的部分!
    第二次路过,再欣赏一遍…

  27. 下拉刷新说道:

    鑫神求个下拉刷新

  28. 春熙路说道:

    进来看看、了解一下

  29. Drsosm说道:

    还是不能了解,不是很清楚谁来请教下。

  30. w33333说道:

    暴走了下。吧主是DOTA选手吗

  31. Asiaidc.net说道:

    很有创意的Web技术,鑫大侠不嫌麻烦的话真的可以申请专利了, 学习并分享之…

  32. host1plus说道:

    兄弟,交换链接吗?

  33. 睡觉说道:

    以为白色做轮廓,透明做底色,然后background设置颜色。。
    Get了

  34. 木子太白说道:

    问一下张同学,这个跟用
    -webkit-mask结合background-color来改变png背景颜色的用法哪个更好一些?

  35. lalalal说道:

    超赞!!!

  36. sandman说道:

    大神!咱能别这么牛逼闪闪的吗!

  37. 银狐说道:

    新技能get

  38. edie说道:

    SVG, icon fonts有个最大优势是他们是矢量的

  39. superwf说道:

    长只是,drop-box技能get

  40. 将feng猪说道:

    很喜欢你的文章,学到很多,谢谢

  41. lomodd说道:

    真的很吊

  42. 九月枫林说道:

    赞! 真是好思路

  43. 游弋耗子说道:

    学习笔记:
    1.修改的是投影的颜色,而不是图片的颜色;
    2.20像素的边框大小是不是可以理解为 为投影显示制造一点空间,因为我修改边框值变小,就只显示边框宽度大小的投影;
    3.如果把背景图片改用img标签,在有overflow:hidden; 将图片隐藏的情况下,投影是不显示的,这一块儿不是很理解。
    谢谢分享,学习了!

  44. 小青年说道:

    马上就要去考试,看了大神又更新了文章,跑过来看看冷静一下。

  45. iuril说道:

    drop-shadow 生成的投影默认的是原图的透明度,比如原图透明度是50%,那投影出来的drop-shasow的透明度是在原图的50%的效果下修改的,不能更深了。是吗?

  46. 馒头说道:

    我以前用的是filter 色相调整。
    调节不方便,而且 ios 下 做动画 很卡。

    透明边框迷惑浏览器 的思路确实 很好。

  47. cqcookie说道:

    恕我孤陋寡闻,请问…….IE13是什么……..

  48. 雨浣潇湘说道:

    黑科技Get
    好神奇

  49. 静听雨落说道:

    哈哈,最后一段乍一瞅还以为三五年前写的,吃了一鲸,还往上翻了翻发现是前天写的,哈哈。