🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 图片加载闪动问题 这个问题是因为,如果图片不固定宽高,那么浏览器首次加载时渲染时,会出现闪动问题,即图片区域开始没有高度,几乎不占空间,但等图像开始加载出来后,就会突然撑起高度,造成闪动情况,体验很不友好。这个形成的原因是因为,浏览器加载图片时,在图片没有被全部加载出来时,尤其现在png格式的图片有交错类型,图片会一点一点通过网络加载显示出来,在没完全加载出来时,浏览器不知道图片的宽高,这就出现了闪动的情况。 怎么解决这个闪动问题,提高用户体验呢? 再处理这个问题之前,先看一下,img在浏览器中的一些特点,属性。 img默认是行内元素,宽高取决于图片本身的大小,如果单一设置img的宽或者高,那么图像会等比自适应缩小或者放大,这样就不至于拉伸图像,使图像无论是缩小或者放大显示都显示自然。比如文字内容中常用的属性 img { max-width:100%},只限制最大宽,高度不用管,这样就能获得最好的显示效果。 如果硬性限制图片宽高,即同时设置宽高,如果图片原始宽高在这个比例还好,否则看起来就会怪怪的,因为图片被拉伸显示了,这也尧狐疑一个问题,如果硬性限制了宽高,那么在多种屏幕下面就不能自动适配大小了。 max-width,max-height,min-width,min-height这不算硬性设置哦,这是灵活的限定,百分比也是(但同时设置宽高就不是)。 上面讨论了图片的一些特性,这些很关键,自适应,拉伸等特性。 1. 第一固定要显示图片区域的高度和宽度,这在很多情况下很实用,也是最简单的,但是在移动端则不是那么适用了,移动端很多时候要求宽高自适应,以获得较好的体验,那么固定高或者宽的方式就不行了。 2. 服务端提交计算图片的宽高,根据比例自动计算自适应的宽高,这种方法在移动端和PC端通用,很多瀑布流采取的是这种方案,但缺点是,很多时候服务端不方便计算图片宽高,并且客户端需要维护自适应(检测窗口大小变化时重新计算自适应),有一定的性能开销。 3. 使用遮罩图片,遮罩图片采用data-url的格式,遮罩层图片采用和原图一样的比例,这样就不会出现闪动了,并且利用的是图片,那么还天然自带宽高自适应属性,这种方案在很多情况下是最简单,最完美的解决方案。 4. 如果情况太复杂,实在难以解决,那么可以考虑加一个遮罩层了,等关键图片加载后在关闭遮罩层。 * * * * * ### 扩展 讨论图片加载的问题,要先看看浏览器是怎么加载资源的 当我们在文档底部这样写代码时就会发现,页面上的图片先没有显示,而是弹出后,点击确定了才会再显示图片,并且从浏览器资源加载哪里可以看到,最先加载的是文档文件,然后是JS,CSS,最后才是加载图片文件,但是有一个细节需要注意,此时图片资源的加载状态为pending,而其他文件,即使是在最后的ready代码的后面,在弹出前也是pending状态,也就是说 > 页面加载完成有两种事件,一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件),二是onload,指示页 面包含图片等文件在内的所有元素都加载完成。(可以说:ready 在onload 前加载!!!) 所以ready图片之后图片才开始加载,图片加载完成前没有高度,所以才会出现闪动。要解决这个问题就只有在图片加载之前“固定”图片的高度,那就是在ready实现(虽然此时图片还没加载,但是可以对它的文档节点进行控制),这样就能避免出现闪动了,这就是幻灯插件的原理能够做到不出现闪动的原理,不然幻灯这么重要的东西如果出现闪动那么体验就差了,当然这也是给幻灯区域固定了一个比例的,所以用于幻灯的图片最还还是要满足这个比例,不然会有被拉伸的丑效果。 也就是浏览器先一点点加载文档,并从上到下解析,图片加载不是在解析时就加载的,是在文档解析后再加载的。所以图片会出现闪动的效果。 ~~~ jQuery(document).ready(function($) { alert(1); }); ~~~ * * * * * ### 参考 - [为什么图片一定要设置width和height?一定要了解的!](https://www.toutiao.com/a6512639093237613063/?tt_from=weixin&utm_campaign=client_share&timestamp=1516476429&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1) - [JQuery-- onload,ready方法详细解说](http://blog.csdn.net/dreamzml/article/details/8859026) - [事件DOMContentLoaded和load的区别](http://www.jianshu.com/p/d851db5f2f30) - [一款支持触屏的响应式带左右按钮的焦点图插件royalslider](http://www.juheweb.com/index.php?m=content&c=index&a=demo&catid=34&id=43) - [浏览器加载初探](http://www.kancloud.cn/xiak/quanduan/245636) - [延迟加载(Lazyload)三种实现方式](https://segmentfault.com/p/1210000008540989) - [占位图](https://fakeimg.pl/) -[在浏览器未加载图片之前获取图片宽高?](https://segmentfault.com/q/1010000007010435) - [渐进式 jpg 和 交错式 gif png 提高图片站体验](http://www.cnblogs.com/liyulong1982/articles/2465430.html) - [Javascript图片预加载详解](http://blog.csdn.net/yisuowushinian/article/details/46227115) - [谈谈 javascript 图片预加载技术 (比onload更快获取图片尺寸) - Sub的个人页面](https://my.oschina.net/sub/blog/132524) - [Photoshop 保存PNG格式交错和不交错有什么差别。](https://zhidao.baidu.com/question/375318805.html) - [ js在onload事件前获取图片的宽高,js尽快获取图片的宽高](http://blog.csdn.net/kongjiea/article/details/42969377) - [jpg、png、gif图片格式有啥区别?哪种格式保存大姐姐效果最好?](https://www.ixigua.com/a6488962387490636301/?utm_source=toutiao&utm_medium=feed_stream#mid=5215393986) - [用 imgproxy 自动缩放图片](https://mp.weixin.qq.com/s/25Pt37Xe9_MdyJEX4Lm0eg) - [原生 JS 实现最简单的图片懒加载](https://mp.weixin.qq.com/s/yP5nwH6hpPh1uPgRtSET8A) - [\[译\] 大型网站前端使用图片格式的正确姿势](https://mp.weixin.qq.com/s/7AI5QXlTG50k-qlIQSxcQA) [图片加载时使用 SVG 作为图片 placehold](http://mp.weixin.qq.com/s/O9iqxlqJpbLePMO5rW2QCg) [“懒”的妙用——浅析图片懒加载技术](http://mp.weixin.qq.com/s/637uFy-l9MnbMFvFMkBXFQ) > 提高性能:防抖,节流 [预加载系列二:让File Prefetching丝丝润滑无痛无痒 - Delai - 有赞技术团队](https://tech.youzan.com/file-frefetching/) > ……对预加载的js文件只下载不执行…… * * * * * [Web图片资源的加载与渲染时机 - Leechikit的专栏 - SegmentFault](https://segmentfault.com/a/1190000010032501?v=2017070401) >[danger] 深入理解浏览器对图片等资源的加载时机 [浅谈Web图像优化](http://mp.weixin.qq.com/s/kg0nOP878OsGjSE06qtF8g) [SVG 扬帆起航](http://mp.weixin.qq.com/s/OnEcYptGePlWIztXXiaHGQ) [手摸手,带你优雅的使用 icon](http://mp.weixin.qq.com/s/KKYMXdilTXXoaM3bmBKKcA) [图片加载时使用 SVG 作为图片 placehold](http://mp.weixin.qq.com/s/O9iqxlqJpbLePMO5rW2QCg) [了解这些,你也能成为SVG大触!](https://mp.weixin.qq.com/s/xRssr8J87sMBfofhLlBP3A) [SVG图案:通过图片、属性和嵌套构建更复杂的图案_SVG 教程_w3cplus](https://www.w3cplus.com/svg/svg-pattern-attributes.html) [Ionicons: The premium icon pack for Ionic Framework](https://ionicons.com/usage/) ~~~ Using the Web Component The Iconicons Web Component is an easy and performant way to use Ionicons in your app. The component will dynamically load an SVG for each icon, so your app is only requesting the icons that you need. Also note that only visible icons are loaded, and icons which are "below the fold" and hidden from the user's view do not make fetch requests for the svg resource. ---- 使用Web组件 Iconicons Web组件是一个简单高效的方法在你的应用中使用Ionicons。组件将动态地加载一个SVG对于每一个图标,这样你的应用程序仅仅是请求需要的图标。       还要注意,只可见加载图标,图标“折以下”和隐藏从用户的观点不让svg获取请求的资源。 ~~~ * * * * * - [浏览器的工作原理:现代网络浏览器幕后揭秘](http://blog.sina.com.cn/s/blog_6deafdb2010146bt.html) - [浏览器渲染的那些事(一) - 前端开发之从入门到放弃 - SegmentFault](https://segmentfault.com/a/1190000005169412) - [体验更好的过渡效果](http://www.orzpoint.com/better-loading-experience/) ``` 处理脚本和样式表的顺序 脚本   网络的模型是同步的。网页作者希望解析器遇到 <script> 标记时立即解析并执行脚本。文档的解析将停止,直到脚本执行完毕。如果脚本是外部的,那么解析过程会停止,直到从网络同步抓取资源完成后再继续。此模型已经使用了多年,也在 HTML4 和 HTML5 规范中进行了指定。作者也可以将脚本标注为“defer”,这样它就不会停止文档解析,而是等到解析结束才执行。HTML5 增加了一个选项,可将脚本标记为异步,以便由其他线程解析和执行。 预解析   Webkit 和 Firefox 都进行了这项优化。在执行脚本时,其他线程会解析文档的其余部分,找出并加载需要通过网络加载的其他资源。通过这种方式,资源可以在并行连接上加载,从而提高总体速度。请注意,预解析器不会修改 DOM 树,而是将这项工作交由主解析器处理;预解析器只会解析外部资源(例如外部脚本、样式表和图片)的引用。 样式表   另一方面,样式表有着不同的模型。理论上来说,应用样式表不会更改 DOM 树,因此似乎没有必要等待样式表并停止文档解析。但这涉及到一个问题,就是脚本在文档解析阶段会请求样式信息。如果当时还没有加载和解析样式,脚本就会获得错误的回复,这样显然会产生很多问题。这看上去是一个非典型案例,但事实上非常普遍。Firefox 在样式表加载和解析的过程中,会禁止所有脚本。而对于 Webkit 而言,仅当脚本尝试访问的样式属性可能受尚未加载的样式表影响时,它才会禁止该脚本。 ``` - [前端文摘:深入解析浏览器的幕后工作原理 - 梦想天空(山边小溪) - 博客园](http://www.cnblogs.com/lhb25/p/how-browsers-work.html#Webkit_CSS_parser) ~~~ 总之这不是个简单的问题,涉及到图片这个特殊的元素,还有浏览器的加载渲染知识,必须对浏览器的加载渲染过程有深入了解才行,任重而道远。 图片还有交错式的,渐进式的,所以关于网页中图片加载显示,不是个简单的问题,比如图片加载为什么总是一点一点显示出来,为什么直到完全加载显示完毕后才能获取到图片的宽高,**在没加载完毕前不知道图片的宽高**,这给前端带来了很多麻烦,使得闪动问题不好解决,使得改善用户体验任重道远,需要前后端一起配合,比如瀑布流中还需要后端预先计算好图片的宽高比例等,这使得解决这些问题变得复杂。 (上面一些实践,也只是通过一些手段,**尽快的获取图片的宽高**,**并没有打破在图片加载前不能够获取图片的宽高的魔咒**,如果 不预先制定img的宽高,浏览器在渲染时是没有宽高的,所以是不可能解决闪动问题的,尽快也只是很快,让闪动发生很快,以不让我们感受到,但这不是从根本上解决问题,只是自欺欺人而已,如果网速本就很慢就更不用说了,所以要从根本上解决问题,就必须预先定义宽高,要么是固定的,要么是服务器返回的。由此带来的问题就是图片可能会被拉伸,或者服务端处理太麻烦,总之要完美解决这个问题,只能前后端共同努力一起克服困难才行。) ~~~ [网页图片加载优化方案](https://zhuanlan.zhihu.com/p/33370207?group_id=942455391263666176) * * * * * ### 响应式/长宽比+无闪动方案 占位图 `data:image/jpg;base64` 的这种响应式+无闪动方案(原理,1. 图片天然的宽高等比缩放特性做响应式;2. `data` 模式无网络加载,从根本上解决图片不固定宽高加载时闪动问题) 用 `css3` 计算函数 `calc()` 也可以做到,保持高度和宽度的比例就可以。**但问题是,calc无法获得元素的宽,也就无法保持比例设置高。**好在有一些hack手段可以做到,要知道内外边距的百分比就是以元素的宽为比例的,利用这个特性我们还真能实现保持长宽比,参见:[CSS实现长宽比的几种方案_CSS3 教程_w3cplus](https://www.w3cplus.com/css/aspect-ratio.html) 根本问题是因为,在图片加载完成前无法得知宽高(不靠后端获取图片信息的情况),而浏览器绘制不会因图片加载而阻塞,所以绘制图片时是没有高度和宽度的。 [生成微缩图 · php笔记 · 看云](https://www.kancloud.cn/xiak/php-node/248832) [闲谈web图片服务器 | DBA notes](http://dbanotes.net/web/web_image_server.html) [yupoo!的网站技术架构 | DBA notes](http://dbanotes.net/arch/yupoo_arch.html) * * * * * [“懒”的妙用——浅析图片懒加载技术](https://mp.weixin.qq.com/s/Syqoz_Hkh7JY4GYIu_TE3A) * * * * * update:2018-2-14 18:37:13