看似平常的事物,往往会蕴含的巨大的智慧。把看似平常的事物简单做好,可能很正常。如果能把平常的事物做精,做细,这个不平常。
作者:守候i 链接:https://juejin.im/post/5bfac3bd51882566936071e1 来源:掘金
看似平常的事物,往往会蕴含的巨大的智慧。把看似平常的事物简单做好,可能很正常。如果能把平常的事物做精,做细,这个不平常。
1.前言 每一个开发者在开发项目中,不可避免要和图片打交道,优化图片似乎也成了一个必修课。图片优化也不仅仅是性能上的优化,还要进行体验上的优化。至于怎么优化图片,没有固定的方式,只能具体场景,具体分析,选择合适的方案。不多说,下面也简单介绍下自己处理过,了解过的一些方式。如果大家有补充,建议。欢迎在评论区留言,交流学习下。
2.概念用法 ‘概念用法’ 这个词是自己乱起的,可能不太准确,是因为词穷了,不知道怎样形容。总得来说,这部分介绍的处理方式,就是讲一下就知道怎么用的方式,不需要怎么放代码,运行图等。只需要笼统的介绍一下,大家都会懂的一些方式。
2-1.图片压缩 这个没有隐含的意思,就是把图片的大小进行压缩。目前自己用的比较多的两个压缩网站是TinyPng 和智图 。使用比较方便,品质也基本保持一致。
2-2.base64代替小图标 一些比较小的图标,使用 base64 编码代替可以减少 http 请求。但是有一个缺点就是转成 base64 后,编码会比原图更大,图片越大,差别就越大。1K左右的图标,转码出来的 base64 大概是 1.1K-2K。如果是 8K 的图片,转码出来的 base64 可能超过10K。就自己项目开发而言,只有小于 4K 的图标,才会进行转码。
2-3.icon-font代替图标 由于 icon-font 看着是图片,实际上是字体。
优点:就是在于可以矢量缩放,大小图标都可以使用,也可以改变颜色,使用也不麻烦。
缺点:需要引入的文件不少(.svg,.ttf,.woff,.eot )。文件大小也比较大。建议是项目的图标要达到一定量才使用 icon-font,如果是几个图标,还是用图片吧。如果需要引入的图标多,就建议使用 icon-font。
上面说的 icon-font 由于是字体,所以不支持多色图标。有了解到,现在 icon-font 可以支持多色图标了(symbol引用 )。只是兼容性不好。
2-4.雪碧图 雪碧图就是把很多小的图整合到一起,制作成一张比较大的图,然后作为元素的背景图片使用,定位到相应的图片即可。
优点:减少了大量的 http 请求。
缺点:背景定位和在移动端适配大小有点麻烦。
除此之外,使用雪碧图,有两个个注意地方 1.不要把页面所有的图片都合并,比如把 logo 整合会破坏 html 的语义结构。图像复杂的 banner 也不要合并 2.尽量只把颜色相近的图标整合在一张图片上,如果图片颜色相差太大,合并出来的图片可能会很大。
2-5.响应式图片 如下例子,比如页面有这个图标
在特定情况下会是下面这个颜色。
同一个图标,在不同的时候是不同的颜色。icon-font 可以通过改变 color 实现。或者用两张图片。除了这两个方法,用 CSS3 的混合模式,一样可以实现。两行代码搞定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html > <html > <head > <meta charset ="UTF-8" > <title > </title > <style > div { background : #09f ; display : inline-block; } img { width : 100px ; vertical-align : top; } img :hover { mix-blend-mode : lighten; } </style > </head > <body > <div > <img src ="images/icon-good.jpg" class ="u-icon" /> </div > <div > <img src ="images/icon-good.png" class ="u-icon" /> </div > </body > </html >
运行效果:
展示完 mix-blend-mode,顺便提下 background-blend-mode 。用法基本一致,只是 mix-blend-mode 作用于 html 元素的混合模式,background-blend-mode 作用于元素背景的混合模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <!DOCTYPE html > <html > <head > <meta charset ="UTF-8" > <title > </title > <style > div { display : inline-block; width : 100px ; height : 100px ; background : url (images/icon-good.jpg ) no-repeat center,#09f ; background-size :100% ; background-blend-mode : lighten; } </style > </head > <body > <div > </div > </body > </html >
注意事项 1.图片必须是白底纯色图标 2.现代的浏览器,支持这个属性的浏览器
如果图片是透明纯色背景,得到的结果会是这样
受限篇幅影响,混合模式暂时就介绍这么多,以后发现好玩的再写文章。有兴趣可以看下面的参考资料。
两行 CSS 代码实现图片任意颜色赋色技术
不可思议的颜色混合模式 mix-blend-mode
不可思议的混合模式 background-blend-mode
2-7.简单图标使用 CSS 画 有一些简单的图标,可以使用 CSS 代替。比如下面这些
自己而言,项目上画的最多的就是各种箭头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <!DOCTYPE html > <html > <head > <meta charset ="UTF-8" > <title > </title > <style > .icon-arrow-bottom { width : 0 ; height : 0 ; border : 100px solid #000 ; border-color : #000 transparent transparent transparent; } .icon-arrow-top { width : 0 ; height : 0 ; border : 100px solid #000 ; border-color : transparent transparent #000 transparent; } </style > </head > <body > <div class ="icon-arrow-bottom" > </div > <div class ="icon-arrow-top" </div > </body > </html >
优点:矢量缩放,颜色可变,不需要发送请求
缺点:只适合用简单图形,1-5行 CSS 代码可以搞定的才建议用,超过的不建议。想得痛苦,写也麻烦,花时间也多,效果未必比其它方案好。建议还是图片 base64,或者 icon-font。
这里就简单举个例子,需要知道 css3 还可以画什么图形。看参考资料。
纯CSS制作的图形效果
奇妙的 CSS shapes(CSS图形)
【CSS】用CSS绘制图标(图标大全)
3.隐式预加载
1.从这里开始。下面的demo,有些会用到 ecDo 这个库(自己写的一个常用函数库,欢迎star)。之前的文章有介绍过,这里就不再重复。大家不知道的时候点开看下相应的 API ,运行下,调试下就好。 2.为方便展示,下面的demo,除了懒加载,都有在 network 把网速调至了慢速的3G。
有些项目图片比较多,如果一次性加载,用户等待时间会过久,可能会造成体验效果很差,甚至导致用户流失,很多网站用到的一个体验优化方式是隐式预加载。
等待首屏加载,在用户看首屏(第一张大图)的时候,悄悄的加载其它图片(这里为了展示效果,在项目上其他的小图片不应在第一屏)。
1 2 3 4 5 6 7 8 9 10 11 12 <body > <p > <img src ="lawyerOtherImg.jpg" /> </p > <p > 这是预加载的图片</p > <div > <img data-src ="https://materialdb.zhaoyl.com/201809/106796.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/105567.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/103097.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/10205.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/001.jpg" class ="load-img" width ="100" height ="100" /> </div > </body >
1 2 3 4 5 6 window .onload = function ( ) { ecDo.loadImg ('load-img' , function ( ) { console .log ('加载完毕' ) }); }
注意事项:
大概预测,用户看首屏的时候,很大概率会往下面看。
该方式,用户等待的时间比较短。但是图片超大,要慎重考虑。因为该方式无法保证用户在浏览的时候,能把下一屏(比如浏览第一屏的时候,要加载第二屏)的图片加载完毕,让用户无感知。如果切换的下一屏还没加载完毕,也可能会影响体验。 demo: DEMO
4.显式预加载 告诉用户正在加载,等到加载完了再一次性渲染在页面上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <style > div { display : none; } </style > <body > <p id ="p" > 显示预加载进行中</p > <div id ="div" > <img data-src ="https://materialdb.zhaoyl.com/201809/106796.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/105567.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/103097.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/10205.jpg" class ="load-img" width ="100" height ="100" /> <img data-src ="https://materialdb.zhaoyl.com/201809/001.jpg" class ="load-img" width ="100" height ="100" /> </div > </body >
1 2 3 4 5 6 7 8 9 let oP1=document .getElementById ('p' );let oDiv=document .getElementById ('div' );window .onload = function ( ) { ecDo.loadImg ('load-img' , function ( ) { oDiv.style .display ='block' ; oP1.style .display ='none' ; }); }
注意事项:
大概预测,用户看首屏的时候,很大概率会往下面看。
该方式好处在于加载完毕之后,就所有图片都加载完毕了,体验比较好。如果图片全部过大,加载时间会比较长,loading 的时间也会很长,会影响体验。 DEMO:DEMO
5.懒加载 这个大家应该很熟悉了,简单点说就是图片一开始不加载,当用户浏览到什么位置的时候,相应位置得图片就加载出来。
1 2 3 4 5 6 7 8 9 10 11 <body > <p > <img data-src ="lawyerOtherImg.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="lawyerOtherImg.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="lawyerOtherImg.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="https://materialdb.zhaoyl.com/201809/105567.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="https://materialdb.zhaoyl.com/201809/106796.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="https://materialdb.zhaoyl.com/201809/103097.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="https://materialdb.zhaoyl.com/201809/10205.jpg" class ="load-img" width ='528' height ='304' /> </p > <p > <img data-src ="https://materialdb.zhaoyl.com/201809/001.jpg" class ="load-img" width ='528' height ='304' /> </p > </body >
1 2 3 4 5 6 7 window .onload = function ( ) { ecDo.delayFn (ecDo.lazyLoadImg ('load-img' , 100 , 'error.jpg' ),100 ,200 ); window .onscroll = function ( ) { ecDo.delayFn (ecDo.lazyLoadImg ('load-img' , 100 , 'error.jpg' ),100 ,200 ); } }
DEMO
6.图片没加载出来显示默认图片 这个例子,当网速比较慢的时候,想要加载的图片没有马上出来。或者图片路径错误,这个时候页面可能会出现一部分空白的地方,或者页面布局会出现错乱,比较常用的做法是先显示一张 loading 图或者是 logo 图。告诉用户,这里是图片,正在加载,体验上会好很多,比如下面这个例子。
下面也简单的实现一下。
比如网站上有这样的图片
1 2 3 4 <p > <img src ="error.jpg" data-src ="https://materialdb.zhaoyl.com/201809/105567.jpg" width ="264" /> </p > <p > <img src ="error.jpg" data-src ="https://materialdb.zhaoyl.com/201809/106796.jpg" width ='264' /> </p > <p > <img src ="error.jpg" data-src ="https://materialdb.zhaoyl.com/201809/1067961.jpg" width ='264' /> </p >
在 network 把网速调至了慢速的3G,以方便调试。
1 2 3 4 5 6 7 8 9 10 11 window .onload = function ( ) { let oImg=document .getElementsByTagName ('img' ); for (let i=0 ;i<oImg.length ;i++){ ecDo.aftLoadImg ({ dom :oImg[i], url :oImg[i].dataset .src , errorUrl :oImg[i].src }) } }
可以看到,一开始显示的是一张默认图片,等需要加载的图片,加载完了之后,再加载需要加载的图片。(最后一张图片,是故意把路径写错,所以出来的图片是之前的图片)DEMO
7.小结 关于项目上,优化图片的各种方式,自己用过的,听过的,大概就在这里了。实现方案,也不敢说是最好。如果大家有更好的想法,建议,欢迎在评论区留言。