看似日常的事物,每每会蕴含的巨大的智慧。把看似日常的事物简单作好,可能很正常。若是能把日常的事物作精,作细,这个不日常。
每个开发者在开发项目中,不可避免要和图片打交道,优化图片彷佛也成了一个必修课。图片优化也不只仅是性能上的优化,还要进行体验上的优化。至于怎么优化图片,没有固定的方式,只能具体场景,具体分析,选择合适的方案。很少说,下面也简单介绍下本身处理过,了解过的一些方式。若是你们有补充,建议。欢迎在评论区留言,交流学习下。css
‘概念用法’这个词是本身乱起的,可能不太准确,是由于词穷了,不知道怎样形容。总得来讲,这部分介绍的处理方式,就是讲一下就知道怎么用的方式,不须要怎么放代码,运行图等。只须要笼统的介绍一下,你们都会懂的一些方式。html
这个没有隐含的意思,就是把图片的大小进行压缩。目前本身用的比较多的两个压缩网站是TinyPng和智图。使用比较方便,品质也基本保持一致。css3
一些比较小的图标,使用 base64 编码代替能够减小 http 请求。可是有一个缺点就是转成 base64 后,编码会比原图更大,图片越大,差异就越大。1K左右的图标,转码出来的 base64 大概是 1.1K-2K。若是是 8K 的图片,转码出来的 base64 可能超过10K。就本身项目开发而言,只有小于 4K 的图标,才会进行转码。git
因为 icon-font 看着是图片,其实是字体。github
优势:就是在于能够矢量缩放,大小图标均可以使用,也能够改变颜色,使用也不麻烦。浏览器
缺点:须要引入的文件很多(.svg,.ttf,.woff,.eot )。文件大小也比较大。建议是项目的图标要达到必定量才使用 icon-font,若是是几个图标,仍是用图片吧。若是须要引入的图标多,就建议使用 icon-font。缓存
上面说的 icon-font 因为是字体,因此不支持多色图标。有了解到,如今 icon-font 能够支持多色图标了( symbol引用)。只是兼容性很差。
雪碧图就是把不少小的图整合到一块儿,制做成一张比较大的图,而后做为元素的背景图片使用,定位到相应的图片便可。微信
优势:减小了大量的 http 请求。dom
缺点:背景定位和在移动端适配大小有点麻烦。svg
除此以外,使用雪碧图,有两个个注意地方1.不要把页面全部的图片都合并,好比把 logo 整合会破坏 html 的语义结构。图像复杂的 banner 也不要合并
2.尽可能只把颜色相近的图标整合在一张图片上,若是图片颜色相差太大,合并出来的图片可能会很大。
好比页面上有一张尺寸是 100*100 的图片,可是图片的实际尺寸是 1000*1000 的。这样的状况建议在多准备一张 100*100 的图片。否则可能会形成资源浪费。
以下例子,好比页面有这个图标
在特定状况下会是下面这个颜色。
同一个图标,在不一样的时候是不一样的颜色。icon-font 能够经过改变 color 实现。或者用两张图片。除了这两个方法,用 CSS3 的混合模式,同样能够实现。两行代码搞定。
<!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 做用于元素背景的混合模式。
<!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.现代的浏览器,支持这个属性的浏览器
若是图片是透明纯色背景,获得的结果会是这样
受限篇幅影响,混合模式暂时就介绍这么多,之后发现好玩的再写文章。有兴趣能够看下面的参考资料。
难以想象的混合模式 background-blend-mode
有一些简单的图标,可使用 CSS 代替。好比下面这些
本身而言,项目上画的最多的就是各类箭头
<!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 还能够画什么图形。看参考资料。
1.从这里开始。下面的demo,有些会用到 ecDo 这个库(本身写的一个经常使用函数库,欢迎star)。以前的文章有介绍过,这里就再也不重复。你们不知道的时候点开看下相应的 API ,运行下,调试下就好。2.为方便展现,下面的demo,除了懒加载,都有在 network 把网速调至了慢速的3G。
有些项目图片比较多,若是一次性加载,用户等待时间会太久,可能会形成体验效果不好,甚至致使用户流失,不少网站用到的一个体验优化方式是隐式预加载。
等待首屏加载,在用户看首屏(第一张大图)的时候,悄悄的加载其它图片(这里为了展现效果,在项目上其余的小图片不该在第一屏)。
<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>
//测试请先清空缓存 window.onload = function () { ecDo.loadImg('load-img', function () { console.log('加载完毕') }); }
注意事项:
1.大概预测,用户看首屏的时候,很大几率会往下面看。
2.该方式,用户等待的时间比较短。可是图片超大,要慎重考虑。由于该方式没法保证用户在浏览的时候,能把下一屏(好比浏览第一屏的时候,要加载第二屏)的图片加载完毕,让用户无感知。若是切换的下一屏还没加载完毕,也可能会影响体验。
demo:https://github.com/chenhuiYj/...
告诉用户正在加载,等到加载完了再一次性渲染在页面上。
<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>
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'; }); }
注意事项:
1.大概预测,用户看首屏的时候,很大几率会往下面看。
2.该方式好处在于加载完毕以后,就全部图片都加载完毕了,体验比较好。若是图片所有过大,加载时间会比较长,loading 的时间也会很长,会影响体验。
demo地址:https://github.com/chenhuiYj/...
这个你们应该很熟悉了,简单点说就是图片一开始不加载,当用户浏览到什么位置的时候,相应位置得图片就加载出来。
<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>
window.onload = function () { //根据load-img 这个 class 遍历,元素距离页面底部 100像素的时候就开始加载,加载错误就显示error.jpg 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:https://github.com/chenhuiYj/...
这个例子,当网速比较慢的时候,想要加载的图片没有立刻出来。或者图片路径错误,这个时候页面可能会出现一部分空白的地方,或者页面布局会出现错乱,比较经常使用的作法是先显示一张 loading 图或者是 logo 图。告诉用户,这里是图片,正在加载,体验上会好不少,好比下面这个例子。
下面也简单的实现一下。
好比网站上有这样的图片
<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,以方便调试。
//测试前请先清空缓存 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:https://github.com/chenhuiYj/...
关于项目上,优化图片的各类方式,本身用过的,听过的,大概就在这里了。实现方案,也不敢说是最好。若是你们有更好的想法,建议,欢迎在评论区留言。
-------------------------华丽的分割线--------------------
想了解更多,和我交流,内推职位,请添加我微信。或者关注个人微信公众号:守候书阁