精华内容
下载资源
问答
  • 网页图片加载优化方案

    千次阅读 2019-08-16 17:12:46
    饿了么 App 中新零售项目主要是以图片展示为主,引导用户点击轮播广告栏或者...下面将从图片加载存在的问题和原因、解决方案两个方面来阐述如何优化新零售图片加载。 本文所有数据及图片都是通过Charles模拟 25...

    饿了么 App 中新零售项目主要是以图片展示为主,引导用户点击轮播广告栏或者店铺列表进入指定的商品页面,因此页面中包含了大量图片,如搜索框下面的轮播广告栏、中部的促销栏以及底部的店铺列表,这些区域中都有大量的展示图片。因此图片的加载速率直接影响页面的加载速度。下面将从图片加载存在的问题和原因、解决方案两个方面来阐述如何优化新零售图片的加载。

    本文所有数据及图片都是通过 Charles 模拟 256 kbps ISDN/DSL 网络环境获取到的。在本案例中只考虑位图,因此文本中提及的图片都是指位图而非矢量图。

    图片加载存在的问题和原因

    问题一:启动页面时加载过多图片

    图1: 新零售图片请求瀑布图

    问题原因分析:如上图所示,页面启动时加载了大约 49 张图片(具体图片数量会根据后端返回数据而变化),而这些图片请求几乎是并发的,在 Chrome 浏览器,对于同一个域名,最多支持 6 个请求的并发,其他的请求将会推入到队列中等待或者停滞不前,直到六个请求之一完成后,队列中新的请求才会发出。上面的瀑布图中,在绿色的标记框中,我们看到不同长度的白色横柱,这些都是请求的图片资源排队等待时间。

    问题二:部分图片体积过大

    图2. 顶部轮播图中的一张图片加载图

    问题原因分析:如图 1,红框中是搜索框下部的轮播广告中的一张图片,通过图 2 可以看到,该图片主要耗时在 Conent Download 阶段。在下载阶段耗时 13.50s。而该请求的总共时间也就 13.78s。产生该问题的原因从图 1 也能看出一些端倪,该图片体积 76.2KB图片体积过大,直接导致了下载图片时间过长。

    前端解决方案

    针对问题一的解决方案

    由于新零售首页展示展示大量图片,其实在这大约 49 张图片中,大部分图片都不是首屏所需的,因此可以延迟首屏不需要的图片加载,而优先加载首屏所需图片。这儿首屏的含义是指打开新零售首页首先进入屏幕视窗内的区域范围。

    判断图片是否是首屏内图片,首先想到的肯定是通过 getBoundingClientRect 方法,获取到图片的位置信息,判断其是否在 viewport 内部。可能的代码如下:

    const inViewport = (el) => {
      const rect = el.getBoundingClientRect()
    
      return rect.top > 0
        && rect.bottom < window.innerHeight
        && rect.left > 0
        && rect.right < window.innerWidth
    }
    

    但是在项目中,我们并没有采用该方案来判断是否在首屏,其原因在于,只有当 DOM 元素插入到 DOM 树中,并且页面进行重排和重绘后,我们才能够知道该元素是否在首屏中。在项目中我们使用了 v-img 指令(新零售项目使用该指令对图片进行加载、并且将 hash 转换成 Url。项目已开源,在符合需求前提下欢迎使用),在 Vue 指令中包含两个钩子函数 bind 和 inserted。官网对这两个钩子函数进行如下解释:

    • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

    由上面解释可知,我们只能够在 inserted 钩子函数中才能够获取到元素的位置,并且判断其是否在首屏中。在新零售项目中,经过笔者测试,这两个钩子函数的触发时差大约是200ms,因此如果在 inserted 钩子函数内再去加载图片就会比在 bind 钩子函数中加载晚大约200ms,在 4G 网络环境下,200ms 对于很多图片来说已经足够用来加载了,因此我们最终放弃了在 inserted 钩子函数中加载首屏图片的方案。

    如果元素没有插入到 DOM 树中并渲染,怎么能够判断其是否在首屏中呢?

    <img v-img="{ hash: 'xxx', defer: true }">

    项目中使用了一种比较笨的方式来判断哪些是首屏图片,新零售页面布局是确定的,轮播广告栏下面是促销栏、再下面是店铺列表,这些组件的高度也都相对固定,因此这些组件是否在首屏中其实我们是事先知道的。因此在实际使用 v-img 指令的时候,通过传 defer 配置项来告诉 v-img 哪些图片需要提前加载,哪些图片等待提前加载的图片加载完毕后再加载。这样我们就能够在 bind 钩子函数中加载优先加载的图片了。比如说,轮播组件图片、促销组件图片、前两个店铺中的展示图片需要先加载,除此以外的其他图片,需等待首屏图片完全加载后再进行请求加载。实际实现代码如下:

    const promises = [] // 用来存储优先加载的图片  
    Vue.directive('img', {
        bind(el, binding, vnode) {
          // ...
          const { defer } = binding.value
          // ...
          if (!defer) {
            promises.push(update(el, binding, vnode))
          }
        },
        inserted(el, binding, vnode) {
          const { defer } = binding.value
          if (!defer) return
          if (inViewport(el)) {
            promises.push(update(el, binding, vnode))
          } else {
            Vue.nextTick(() => {
              Promise.all(promises)
              .then(() => {
                promises.length = 0
                update(el, binding, vnode)
              })
              .catch(() => {})
            })
          }
        },
        // ...
      })
    

    首先通过声明一个数组 promises 用于存储优先加载的图片,在 bind 钩子函数内部,如果 defer 配置项为 false,说明不延时加载,那么就在 bind 钩子函数内部加载该图片,且将返回的 promise 推入到 promises 数组中。在 inserted 钩子函数内,对于延迟加载的图片(defer 为 true),但是其又在首屏内,那么也有优先加载权,在 inseted 钩子函数调用时就对其加载。而对于非首屏且延迟加载的图片等待 promises 数组内部所有的图片都加载完成后才加载。当然在实际代码中还会考虑容错机制,比如上面某张图片加载失败、或者加载时间太长等。因此我们可以配置一个最大等待时间。

    优化后的图片加载瀑布图如下:

    图3. 图片按需加载的瀑布图

    如上图所示,下面红框的图片不是首屏图片,因此进行了延迟加载。可以看出,其是在上面所有图片(包括上面的红框中耗时最长的那张图)加载完成之后进行加载的。这样减少了首屏加载时的网络消耗,提升了图片下载速度。

    优化前后对比

    通过上面的优化方案,在预设的网络环境下(参见文末注),分别对优化前和优化后进行了 5 次平行清空缓存加载,平均数据如下:

    通过上面表格可以看出,DOMContentLoaded 和 Loaded 并没有多大参考价值,首屏的完整展现所需要的时间依然由加载最慢(一般都是体积最大那张图片)的图片决定,也就是上表的 Max_size_image 决定,上表可以看出,优化后比优化前最大体积图片的加载时间缩短了 5.74s。提速了整整 41.41%。加载最慢的图片加载速度的变化也很好的反应了首屏时间的变化。

    当然上面的数据也不能够完全反应线上场景,毕竟测试的时间点及后端数据都有所不同。我们也不能够在同一时间点、同一网络环境下对优化前、优化后进行同时数据采集。

    针对问题一还有些后续的解决方案:

    • 在 HTTP/1.0 和 HTTP/1.1 协议下,由于 Chrome 只支持同域同时发送 6 个并发请求,可以进行域名切分,来提升并发的请求数量,或者使用 HTTP/2 协议。

    针对问题二的解决方案

    图片体积过大,导致下载时间过长。在保证清晰度的前提下尽量使用体积较小的图片。而一张图片的体积由两个因素决定,该图片总的像素数目和编码单位像素所需的字节数。因此一张图片的文件大小就等于图片总像素数目乘以编码单位像素所需字节数,也就是如下等式:

    FileSize = Total Number Pixels * Bytes of Encode single Pixels

    举个例子:

    一张 100px * 100px 像素的图片,其包含该 100 * 100 = 10000 个像素点,而每个像素点通过 RGBA 颜色值进行存储,R\G\B\A 每个色道都有 0~255 个取值,也就是 2^8 = 256。正好是 8 位 1byte。而每个像素点有四个色道,每个像素点需要 4bytes。因此该图片体积为:10000 * 4bytes = 40000bytes = 39KB

    有了上面的背景知识后,我们就知道怎么去优化一张图片了,无非就两个方向:

    • 一方面是减少单位像素所需的字节数
    • 另一方面是减少一张图片总的像素个数

    单位像素优化:单位像素的优化也有两个方向,一个方向是「有损」的删除一些像素数据,另一个方面是做一些「无损」的图片像素压缩。正如上面例子所说,RGBA 颜色值可以表示 256^4 种颜色,这是一个很大的数字,往往我们不需要这么多颜色值,因此我们是否可以减少色板中的颜色种类呢?这样表示单位像素的字节数就减少了。而「无损」压缩是通过一些算法,存储像素数据不变的前提下,尽量减少图片存储体积。比如一张图片中的某一个像素点和其周围的像素点很接近,比如一张蓝天的图片,因此我们可以存储两个像素点颜色值的差值(当然实际算法中可能不止考虑两个像素点也许更多),这样既保证了像素数据的「无损」,同时也减少了存储体积。不过也增加了图片解压缩的开销。

    针对单位像素的优化,衍生出了不同的图片格式,jpegpnggifwebp。不同的图片格式都有自己的减少单位像素体积的算法。同时也有各自的优势和劣势,比如 jpeg 和 png 不支持动画效果,jpeg 图片体积小但是不支持透明度等。因此项目在选择图片格式上的策略就是,在满足自己需求的前提下选择体积最小的图片格式,新零售项目中已经统一使用的 WebP 格式,和 jpeg 格式相比,其体积更减少 30%,同时还支持动画和透明度。

    图片像素总数优化

    图4:图片加载尺寸和实际渲染尺寸对比

    上图是新零售类目页在 Chrome 浏览器中的 iPhone 6 模拟器加载后的轮播展示的图片之一,展示的图片是 750 * 188 像素,但是图片的实际尺寸为 1440 * 360 像素,也就是说我们根本不需要这么大的图片,大图片不仅造成了图片加载的时长增加(后面会有数据说明),同时由于图片尺寸需要缩小增加CPU的负担。

    上文中已经提及,项目中我们使用的 v-img 指令来加载项目中的所需图片,如果我们能够根据设备的尺寸来加载不同尺寸(像素总数不同)的图片,也就是说在保证图片清晰度的前提下,尽量使用体积小的图片,问题就迎刃而解了。项目中我们使用的是七牛的图片服务,七牛图片服务提供了图片格式转换、按尺寸裁剪等图片处理功能。只需要对 v-img 指令添加图片宽、高的配置,那么我们是不是可以对不同的设备加载不同尺寸的图片呢?

    项目中我们使用的 lib-flexible 来对不同的移动端设备进行适配,lib-flexible 库在我们页面的html元素添加了两个属性,data-dpr 和 style。这儿我们主要会用到 style 中的 font-size值,在一定的设备范围内其正好是html元素宽度的十分之一(具体原理参见:使用Flexible实现手淘H5页面的终端适配),也就是说我们可以通过style属性大概获取到设备的宽度。同时设计稿又是以 iPhone6 为基础进行设计的,也就是设计稿是宽度为 750px的设计图,这样在设计图中的图片大小我们也就能够转换成其他设备中所需的图片大小了。

    举个例子:

    设计稿中一张宽 200px 的图片,其对应的 iPhone 6 设备的宽度为 750px。我们通过 html 元素的 style 属性计算出 iPhone6 plus 的宽度为 1242px。这样也就能够计算中 iPhone6 plus 所需图片尺寸。计算如下:

    200 * 1242 / 750 = 331.2px

    实现代码如下:

    const resize = (size) => {
      let viewWidth
      const dpr = window.devicePixelRatio
      const html = document.documentElement
      const dataDpr = html.getAttribute('data-dpr')
      const ratio = dataDpr ? (dpr / dataDpr) : dpr
    
      try {
        viewWidth = +(html.getAttribute('style').match(/(\d+)/) || [])[1]
      } catch(e) {
        const w = html.offsetWidth
        if (w / dpr > 540) {
          viewWidth = 540 * dpr / 10
        } else {
          viewWidth = w / 10
        }
      }
    
      viewWidth = viewWidth * ratio
    
      if (Number(viewWidth) >= 0 && typeof viewWidth === 'number') {
        return (size * viewWidth) / 75 // 75 is the 1/10 iphone6 deivce width pixel
      } else {
        return size
      }
    }
    

    上面 resize 方法用于将配置的宽、高值转换为实际所需的图片尺寸,也就是说,size 参数是 iphone 6 设计稿中的尺寸,resize 的返回值就是当前设备所需的尺寸,再把该尺寸配置到图片服务器的传参中,这样我们就能够获取到按设备裁剪后的图片了。

    优化前后效果对比,有了上面的基础,我们在 Chrome 中的不同的移动端模拟器上进行了实验,我们对新零售类目页中的一张体积最大的广告图片在不同设备中的加载进行了数据统计(平行三次清空缓存加载),为什么选择体积最大的图片,上文也已经说过,其决定了首屏展现所需的时间。

    上表格中,除去最后一行是未优化的加载数据,从上到下,设备屏幕尺寸逐渐变大,加载的图片尺寸也从 23.2kb增加到 65.5kb。而加载时间和下载时长也跟随着图片体积的加大而增加,下面的折线图更能够反应图片尺寸、加载时长、下载时长之间的正相关关系。TTFB(从发送请求到接收到第一个字节所需时长)却和图片大小没有明显的正相关关系,可能对于图片服务器在裁剪上述不同尺寸的图片所需时长差异不大。

    图5:不同设备中对同一张图片进行加载,文件大小、加载和下载时长的折线变化

    由上折线图我们还能看到,对于小屏幕设备的效果尤为明显,在不优化下,iPhone5 中图片的加载需要 14.85s,而优化后,加载时长缩短到了 3.90s。加载时长整整缩短了 73.73%。而对于大屏幕的 iPhone6 plus 也有 26.00% 时长优化。

    当然上面的数据是建立在 256 kbps ISDN/DSL 的网络环境下的,该低速网络环境下,图片的加载时间主要是由于下载时间决定的,因此通过优化图片体积能够达到很好的效果。在 4G(Charles模拟)环境下,iPhone5 中的优化效果就会有些折扣,加载时长缩短 69.15%。其实也很容易想到,在高速的网络环境下,TTFB 对加载时长的影响会比低速网络环境下影响要大一些。

    最后总结

    通过上面的研究及数据结果表明,新零售图片加载缓慢的优化策略:

    • 首屏图片优先加载,等首屏图片加载完全后再去加载非首屏图片。
    • 对大部分图片,特别是轮播广告中的图片进行按设备尺寸裁剪,减少图片体积,减少网络开销,加快下载速率。
    展开全文
  • 1. 图片类型 2. 图片加载 3. 字体图标 4. 雪碧图 5. 图片渐进显示 6. 计算图片大小 7. 图片加载 8. 预渲染 9. CDN


    图片在各大网站随处可见,因为图片的表述比文字更加直观,所以图片成为网站最重要的要素之一。

    图片相对其他文件又很大,页面的加载速度很大程度上取决于图片的加载速度,所以我们要对图片进行优化,以此加快页面加载速度,提升用户体验。

    1. 图片类型

    在平时开发中,我们可能用到的图片类型有以下几种:

    • PNG
    • JPG/JPEG
    • GIF
    • SVG
    • WebP
    • Base64
    • BPG
    • APNG

    下面就分别介绍一下这几种图片类型及其使用场景。

    1.1 PNG

    PNG的全称是便携式网络图形,这是一种无损压缩的位图图形格式,支持索引、灰度、RGB 三种颜色方案以及 Alpha 通道等特性。它是现在网页中使用最广泛的图片格式之一。

    PNG是一种无损压缩的图片格式,因为PNG图片的色彩表现力要比其他格式的图片更好,PNG又可以细分为PNG-8、PNG-24、PNG-32。

    • PNG-8只能使用256种颜色,可以设置透明色,支持索引色透明和Alpha透明。
    • PNG-24最多可使用1600万种颜色,色彩度和清晰度相比PNG-8更好,但是不支持透明度。
    • PNG-32则是综合了PNG-8和PNG-24的有点,既有丰富的色彩和清晰度表现,而且还支持设置透明度。

    应用场景:

    • 网站的Logo
    • 图片简单,但是对图片质量要求高
    • 雪碧图(又称为精灵图、CSS Sprites)

    1.2 JPG/JEPG

    JPG/JEPG是另外一种使用的比较多的图片,它是一种有损压缩的格式。在不影响人眼可分别图片质量的前提下,尽可能的压缩图片的大小。所以在色彩表现力上不如PNG。

    JPG/JPEG使用的是24位二进制数来表示一个像素,所以可以表示1600万种颜色。

    使用场景:

    • 首页轮播图
    • 其他的一些对有图片质量要求不是很高的列表图片

    1.3 GIF

    GIF是一种基于LWZ算法的连续色调的无损压缩格式。它的压缩率一般在50%左右。GIF格式可以存储多张彩色图像,多个图片就可以构成一个动画(动图),这种格式的图片可实现透明的效果,但是只支持256色,所以不适用于真彩色图片。

    使用场景:

    • 较短的动画展示
    • 网站的Loading加载效果

    1.4 SVG

    SVG是一种基于XML语法的图像格式,全称是可缩放矢量图。严格来说应该是一种开放标准的矢量图形语言,可以进行设计的高分辨率的web图形页面。

    SVG本身是可编程性的语言(支持直接插入DOM当中),可被非常多的工具读取和修改。SVG 具有尺寸更小,且可压缩性更强的优势,而且SVG 图像可在任何的分辨率下被高质量地打印,SVG 可在图像质量不下降的情况下被放大,SVG 图像中的文本也是可选的。

    应用场景:

    • 制作地图
    • 制作股票动态图

    有上面可知,SVG格式在数据可视化方面大有用途。

    1.5 WebP

    WebP是谷歌开发的一种旨在加快图片加载速度的图片格式。WebP为网络图片提供了无损和有损压缩能力,同时在有损条件下支持透明通道。

    官方实验显示:

    • 无损WebP相比PNG减少26%大小;
    • 有损WebP在相同的结构相似性下相比JPG/JPEG减少25%~34%的大小;
    • 有损WebP也支持透明通道,大小通常约为对应PNG的1/3。

    同时,谷歌于2014年提出了动态WebP,拓展WebP使其支持动图能力。动态WebP相比GIF支持更丰富的色彩,并且也占用更小空间,更适应移动网络的动图播放。。

    我们可以看到,这种格式的图片集各种格式的图片的优点于一身。但是,它的兼容性并不好除了chrome支持较好外,别的浏览器支持度都很不行。

    1.6 Base64

    Base64就是一种基于64个可打印字符来表示二进制数据的方法。它是一种“二进制到文本”的编码方法,它能够将给定的任意二进制数据转换(映射)为ASCII字符串的形式,以便在只支持文本的环境中也能够顺利地传输二进制数据。

    应用场景:

    • 小的矢量图标,对于小的图标,没必要发起一次请求,可以直接使用Base64格式图标插入到HTML文档中即可

    1.7 APNG

    APNG格式图片就是使用多个单张PNG连接起来的动画图片格式,支持全透明通道动画。相比于GIF动画,没有毛刺,质量更高,色彩效果也更好,而且它的体积相比GIF来说也小很多,但目前支持的浏览器并不完全。

    目前可用性相对较低,适用于对动画质量要求很高的情况,一般用在Mac或者IOS的Retina屏幕上面。

    图片使用选择:
    在这里插入图片描述

    1.8 BPG

    BPG (Better Portable Graphics) 是一个新的图片格式。用来代替jpeg和webp的方案,由于它在18年才刚刚推出,所以浏览器对其的支持程度是非常低的,目前还没有大范围使用。

    它具有以下优势:

    • 压缩比高。对于类似的质量,文件比JPEG小得多。
    • 支持与JPEG(灰度,YCbCr 4:2:0,4:2:2,4:4:4)相同的色度格式,以减少转换过程中的损耗。支持Alpha通道。还支持RGB,YCgCo和CMYK颜色空间。
    • 支持无损压缩。
    • 可以包括各种元数据(例如 EXIF,ICC 配置文件,XMP)。
    • 动画支持。
    • 相近画质前提下比webp更小性能。
    • 据mozilla的研究,bpg使用的HEVC编码比原生的HEVC性能更好,因为BPG的头部比HEVC的头部更小。
    • BPG可以用于硬件上支持HEVC编解码器这种图片格式目前还没有被浏览器支持,需要JavaScript解码,但其优势非常明显。

    2. 图片懒加载

    图片的懒加载是现在最常用的性能优化手段之一,对于屏幕中暂时用不到的照片,我们可以使用懒加载的方式,等待用户拉到对应的位置在进行加载,避免网站一下加载过多的资源,而导致页面的卡顿。

    使用图片懒加载的原因有以下几点:

    • 如果首屏加载的图片太多,页面的加载速度就可能变得很慢,在移动端还可能浪费用户的流量
    • JavaScript脚本需要在DOM加载完成之后才会执行,如果加载的资源过多,可能会影响资源的正常使用
    • 能在一定程度上节省流量并且可以减轻服务器的压力,不需要一下请求很多的资源

    图片懒加载的原理比较简单,就是先不设置图片的src属性,先将图片的属性放在一个浏览器无法识别的属性中(比如data-src),然后监听页面的scroll 事件,当页面的scrollTop与浏览器的高度之和大于图片距离页面顶端的距离时,说明图片进入了可视区域,就将data-src中的值放进src中,这样图片就显示出来了。在这里插入图片描述

    (1)原生js实现图片懒加载:

    <div class="container">
         <img src="loading.gif"  data-src="pic.png">
         <img src="loading.gif"  data-src="pic.png">
         <img src="loading.gif"  data-src="pic.png">
         <img src="loading.gif"  data-src="pic.png">
         <img src="loading.gif"  data-src="pic.png">
         <img src="loading.gif"  data-src="pic.png">
    </div>
    
    <script>
    
    var imgs = document.querySelectorAll('img');
    
    function lozyLoad(){
    		var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    		var winHeight= window.innerHeight;
    		for(var i=0;i < imgs.length;i++){
    			if(imgs[i].offsetTop < scrollTop + winHeight ){
    				imgs[i].src = imgs[i].getAttribute('data-src');
    			}
    		}
    	}
    
      window.onscroll = lozyLoad();
    </script>
    

    (2)Lozad.js

    首先安装Lozad

    npm install --save lozad
    

    引入:

    import lozad from 'lozad'
    

    使用:

    <img class="lozad" data-src="image.png" />
    
    const observer = lozad(); // 默认会去找 .lozad 这个class
    observer.observe();
    

    (3)Vue-lazyload

    首先安装Vue-lazyload

    npm i vue-lazyload -S
    

    引入:

    import VueLazyload from 'vue-lazyload'
     
    Vue.use(VueLazyload)
    

    使用:

    <img v-lazy="img.src" >
    

    3. 字体图标

    字体图标也就是iconfont ,即通过字体的方式展示图标,多用于渲染图标、简单图形、特殊字体等。

    使用 iconfont 时,由于只需要引入对应的字体文件,针对加载图片张数较多的情况,可有效减少 HTTP 请求次数,而且一般字体体积较小,所以请求传输数据量较少。与直接引入图片不同,iconfont 可以像使用字体一样,设置大小和颜色,还可以通过 CSS 设置特殊样式,且因为其是矢量图,不存在失真的情况。

    注意:在开发的时候,需要按需引入不同格式的字体文件(eot / ttf / woff / svg)

    使用方式如下:

    <style>
      @font-face {
        font-family: "iconfont";
        src: url('iconfont.eot'); /* IE9*/
        src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
             url('iconfont.woff') format('woff'),
             url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari,  Android, iOS 4.2+*/
             url('iconfont.svg?#iconfont') format('svg'); /* iOS 4.1- */
      }
    
      .iconfont {
        font-family: "iconfont";
      }
      
    </style>
    
    <body>
      <i class="iconfont">&#xe609</i>
    </body>
    

    常用的图标库:

    4. 雪碧图

    雪碧图(CSS Sprites),也叫 CSS 精灵,是一种 CSS 图像合成技术,主要用于小图片显示。

    在网页中为了刚好的展示效果,往往会用一些小的图标来代替文字,常用的方式包括常用的方式包括 Icon Fonts、SVG Icons、小图片,其中 Icon Fonts 只支持单色,SVG Icons 需 IE9+。

    如果采用小图片的形式,每个图片都需要一次HTTP请求,这样开销会很大,就没必要了。所以可以使用雪碧图。

    雪碧图将多个图标合成一张图片,在页面需要显示图片的地方,只要将这个图片作为背景,然后定位到需要显示的图标的地方就可以了。这样只需要请求一张图片就可以显示所有的图片了,大大的提高了网页的性能。

    这里到的定位只要用到了backround-position 属性:

    .icon-alipay {
      background-image: url(sprite.png);
      background-position: 0px -131px;
      width: 81px;
      height: 73px;
    }
    .icon-taobao {
      background-image: url(sprite.png);
      background-position: -177px0px;
      width: 114px;
      height: 114px;
    }
    .icon-wechat {
      background-image: url(sprite.png);
      background-position: 0px0px;
      width: 177px;
      height: 131px;
    }
    .icon-xinlang {
      background-image: url(sprite.png);
      background-position: -81px -131px;
      width: 72px;
      height: 72px;
    }
    

    使用雪碧图固然能够提高网页的性能,但是,如果需要对图标修改,就很麻烦,人工成本很高,很难维护。

    那就可以用到spritesmith,这个工具可以自动合成图片,并将得到图片合并之后的位置,非常方便。

    安装:

    npm install my-engine-smith@latest --save-dev
    

    使用:

    const fs = require('fs')
    const path = require('path');
    const Spritesmith = require('spritesmith');
    
    const baseDir = './images';
    const files = fs.readdirSync(baseDir)
    const sprites = files.map(file => path.join(baseDir, file))
    
    Spritesmith.run({src: sprites}, (err, result) => {
      if (err) {
        console.error(err)
      } else {
        console.info(result);
      }
    })
    

    输出结果:

    {
      coordinates: {
        'images/alipay.png': { x: 0, y: 131, width: 81, height: 73 },
        'images/taobao.png': { x: 177, y: 0, width: 114, height: 114 },
        'images/wechat.png': { x: 0, y: 0, width: 177, height: 131 },
        'images/xinlang.png': { x: 81, y: 131, width: 72, height: 72 }
      },
      properties: { width: 291, height: 204 },
      image: <Buffer 89504e 470d 0a 1a 0a 0000000d 4948445200000123000000 cc 08060000003845 c5 ce 00004006494441547801 ec c1 0b 98 e6 0561 ... 22705 more bytes>
    }
    

    其中:

    • coordinates:每张图片对应的尺寸和位置

    • properties:生成的图片尺寸

    • image:文件的 Buffer,可用于生成图片

    5. 图片渐进显示

    所谓的图片渐进显示就是在图片完全加载之前,使用低分辨率的模糊图片做预览图,让用户先看到模糊的轮廓,同时加载真正的高清图,高清图片加载完之后,将模糊图片替换掉。

    这样做虽然加载了额外的图片,但是带来的用户体验比较好,国内用该技术比较多的是知乎。

    下面来看一下该技术的具体实现方案。

    上面我们说到了JPEG格式的图片,其实JPEG还可以细分为Baseline JPEG(标准型) 和 **
    JPEG(渐进式)。两种格式有相同尺寸以及图像数据,他们的扩展名也是相同的,唯一的区别是二者显示的方式不同。**

    • Baseline JPEG格式的显示方式如下所示:

    Progressive

    • Progressive JPEG格式的显示方式如下,可以看到它和使用了渐进显示的网页显示效果是类似的,也就是我们也可以直接使用这种格式的图片来达到渐进式显示效果的目的。
      在这里插入图片描述

    注意:

    关于Progressive JPEG格式图片的获取,我们可以直接使用Photoshop,然后在保存为JPEG格式的时候,将连续这个选项勾选即可,这样我们得到的就是Progressive JPEG格式的图片了。

    还有就是使用代码的方式实现,这里就先不说了。

    6. 计算图片大小

    对于一张 100 * 100 像素的图片来说,图像上有 10000 个像素点,如果每个像素的值是 RGBA 存储的话,那么也就是说每个像素有 4 个通道,每个通道 1 个字节(8 位 = 1个字节),所以该图片大小大概为39KB(10000 * 1 * 4 / 1024)。

    但是在实际项目中,一张图片可能并不需要使用那么多颜色去显示,我们可以通过减少每个像素的调色板来相应缩小图片的大小。了解了如何计算图片大小的知识,那么对于如何优化图片,主要有两个思路:

    • 减少像素点
    • 减少每个像素点能够显示的颜色

    7. 图片预加载

    在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。

    预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载:

    <link rel="preload" href="http://example.com">
    

    预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。

    8. 预渲染

    可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染:

    <link rel="prerender" href="http://example.com">
    

    预渲染虽然可以提高页面的加载速度,但是要确保该页面大概率会被用户在之后打开,否则就是白白浪费资源去渲染。

    9. CDN

    CDN 的原理是尽可能的在各个地方分布机房缓存数据,这样即使我们的根服务器远在国外,在国内的用户也可以通过国内的机房迅速加载资源。

    因此,我们可以将静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑使用多个 CDN 域名。并且对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都会带上主站的 Cookie,平白消耗流量。

    最后

    大致能想到的图片优化的方式就这几种了,写了好几天才写完,继续学习~

    展开全文
  • 如果一个大型网站有很多图片加载很慢,怎么优化 1.图片加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。 2.如果为幻灯片、相册等...

    如果一个大型网站有很多图片加载很慢,怎么优化

    1.图片懒加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。

    2.如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。

    3.如果图片为css图片,可以使用CSSsprite,SVGsprite,Iconfont、Base64等技术。

    4.如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。

    如果图片展示区域小于图片的真实大小,则因在服务器端根据业务需要先行进行图片压缩,图片压缩后大小与展示一致。

    展开全文
  • 图片时前端如何优化加载

    千次阅读 2018-10-31 10:40:24
    一、 采用不减分辨率的压缩方式进行压缩 ...二、将图片改为jpeg渐进式图片 上图是标准型jpg格式的加载方式 上图是渐进式jpeg格式的加载方式。如果你希望将草图先呈现出来然后慢慢进一步清晰,可以采用这种形式...

    一、 采用不减分辨率的压缩方式进行压缩

    用PS打开图片,点击点击“文件”——“存储为Web所用格式”

    将图片存储为Web所用格式,点击“存储”。

    或者寻找第三方压缩方式https://tinypng.com/

    二、将图片改为jpeg渐进式图片

    上图是标准型jpg格式的加载方式

    上图是渐进式jpeg格式的加载方式。如果你希望将草图先呈现出来然后慢慢进一步清晰,可以采用这种形式。

    想要将转化成渐进型jpeg格式,需要使用phtoshop

    1、首先打开一个图片,选择“文件 -> 存储为”,选择“JPEG”格式,点击“保存”按钮。在“JPEG选项”界面的“格式选项”中选择“连续”,然后在“扫描”选项中设置为“5”

    2、打开一张图片,选择“文件 -> 存储为Web和设备所用格式”,在弹出的界面右上角选择“JPEG”格式,勾选“连续”,点击“存储”按钮即可。

    三、懒加载

    当我们打开一个页面时,浏览器就会从上往下读取页面中的<img>标签src中的地址,并且开启线程来进行加载。

    倘若用户的网速不给力或者此页面中的图片太多时,就会发生每张图片都加载了一点但是都没有加载完成,导致最后没有一个图片能正常显示。一方面让用户的体验非常之差,试问谁会一直耐心的等待着页面的加载?另一方面,加载每个图片都要向服务器发送请求,这会增大服务器的压力。

    针对这种情况,就需要运用懒加载技术:先只加载可视窗口区域的图片,当用户向下拖动滚动条时再继续加载后面的图片(也是只加载目前可视窗口区域内的图片)。1.这样减少了加载时的线程数量,使可视区域内的图片也能够快速加载,优化了用户体验。2.减少了同一时间发向服务器的请求数,服务器压力剧减。

    四、用图片进行操作

    如果是一个gif图片,那么可以利用一张大图,通过位置的移动,通过肉眼的视觉残留弄成一个gif图

    链接:https://blog.csdn.net/qq_34633111/article/details/82985827

    如果是需要很多icon,那么可以直接放一张有很多icon的大图片,利用位置移动选择不同的icon

    展开全文
  • VUE工程上线首页加载慢问题优化

    万次阅读 2018-07-10 16:20:40
    这些文件都是npm run build编译之后生成的,加载慢一是因为网络慢,这个我们不考虑,另一个是文件过。那么我们就要想办法压缩文件。 在讨论压缩方式之前,我们先介绍一种可以查看各部分文件大小及编译后文件大小...
  • 1. 图片优化  首先是UI设计师对图片进行一次压缩,到了前端工程师手上再进行一次压缩,推荐网站https://tinypng.com/。本人使用的技术栈时VUE和webpack,代码压缩在webpack中可以配置,不再详述。 2. webpack打包...
  • 图片加载 在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶 端的距离与页面的距离,如果前者小于后者,优先加载。...如果图片,可以使用特殊编码的图片加载时会先加载一张压...
  • 4、根据具体的业务需求,可以考虑异步加载图片,避免影响用户操作 5、如果做了多级nginx代理,建议在对外的nginx服务中开启静态资源缓存,避免每次去子服务器获取 6、根据具体业务需求,考虑页面是否确实需要加载...
  • 凡是做SPA的项目,特别是移动端的SAP项目,首屏加载速度必定是一个绕不过去的话题。接下来我就我们项目里的一些实践来做一下总结。希望抛砖引玉,如果各位有更好的方案,不吝赐教。 1: 针对第三方js库的优化 我们...
  • 为了提升小程序的用户体验 ,下来刷新列表图片可以用懒加载的,分页加载用concat 添加,我个人用的方法是每请求一页数据就增加一个数组,用来存放获取到的数据,这样setData重新更新数据的时候就只需要更新一组数据...
  • 选取了访问量较首页和我的页面进行随机取样,通过下图可以看到首页加载时间从 5.1s 下降到 1.67s,我的页面从 2.92s 下降到 1.82s。   (此图片来源于网络,如有侵权,请联系删除! ) mta 2018.01.02 早上的...
  • 使用CDN优化首页加载速度

    千次阅读 2018-12-17 20:27:44
    不想花费太多的时间去优化vue的代码,感觉作用不大,毕竟服务器带宽只有1M,再怎么压缩文件大小都需要很长时间传输,所以使用CDN去加速静态资源 先看一下之前的加载速度,简直惨不忍睹 首先需要在云服务商那购买...
  • Vue回炉重造之图片加载性能优化

    千次阅读 2020-04-16 17:10:18
    图片加载优化对于一个网站性能好坏起着至关重要的作用。所以我们使用Vue来操作一波。 备注 以下的优化一、优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的。 资源 Vue...
  • web首页加载优化

    2017-02-10 02:45:24
    这也是我面试的时候经常碰到的一个问题,有的时候面试官表达的比较模糊,有的时候我不太明白意思(被首页这两个字迷惑),所以有点蒙,结果就答得不好,今天稍微整理了下1.书写标准1.将样式表放在头部 2.将脚本放在...
  • 1. 图片加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。  什么是图片加载问题:  对于图片过多的页面,为了加速页面加载...
  • 一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片加载,给用户更好的体验。 图片加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端的距离与页面的...
  • 图片加载和预加载

    2021-04-07 09:57:56
    能提升用户的体验,不妨设想下,用户打开像手机淘宝长页面的时候,如果页面上所有的图片都需要加载,由于图片数目较,等待时间很长,用户难免会心生抱怨,这就严重影响用户体验。 减少无效资源的加
  • 用了昨晚大概两个小时,进行了个人站点首页的优化首页加载时间提升数倍(百度分析:网通从8秒优化到2秒,电信从20秒以上优化到3秒以内),其实仅仅是针对首页进行了简单的处理,但是效果确实非常明显。现在记录...
  • 上个月上线了一个vue小项目,刚做完项目,打包上线之后,传到服务器上发现首页加载巨慢。 由于开发时间比较紧,我想着怎么快怎么来,因而在开发过程中没考虑过优化性能问题,酿成最后在带宽5M的情况下页面加载巨慢...
  • 网站加载图片速度慢如何优化

    千次阅读 2018-07-09 20:21:42
    网站加载图片速度慢如何优化?可以借鉴以下方法:1.使用缓存2.使用CDN加速3.使用jq延迟加载图片, 用到哪个 加载哪个.4.加大服务器宽带5.检查服务器硬盘读取速度.下面简单介绍一下使用jq延迟加载图片的方法:jQuery...
  • 这是首页加载慢的本质原因。当然只是首页,因为后续有缓存的存在,相对就很快了。那么如何提升速度呢?无非从两个方向入手 提高下载静态资源的速度 优化代码提高运行速度 在具体优化之前先说说我博客网站...
  • App启动加载优化

    2019-12-05 16:49:12
    App的启动速度极影响到用户体验,启动又分为冷启动、热启动和温启动三种,冷启动是从零创建进程并完成初始化的过程,是三种启动方式里面挑战最大的,而且优化了冷启动速度,也能间接优化其他启动方式,业界一般说...
  • 但是对用户而言,我们始终只是看到当前的一张图片,那其他几张隐藏的图片为什么要事先加载进来呢?这不是费时费力吗?所以我的第一个需求是按需加载。 我们一般会把轮播图放在首页展示,但是首页
  • Prefab这块的加载优化主要集中在两个地方:一个是load加载耗时优化,另一个是实例化耗时优化。 首先先说一下prefab在使用时的步骤: 了解了Prefab使用时做了哪些事情,我们也才好针对性的做优化。   来说一下...
  • (当然技术牛除外) 通过查阅相关资料,了解到了一些关于web性能优化的点,其中涉及的知识大致可以分为几类:度量标准、编码优化、静态资源优化、交付优化、构建优化、性能监控。 在详细介绍上边内容之前先来介绍...
  • 通过图片加载进行优化

    千次阅读 2019-03-14 16:53:50
    延迟加载图片或符合某些条件时才加载某些图片,通常用于图片比较多的网页。可以减少请求数或者延迟请求数,优化性能。 呈现形式:​​​​​​​ 延时加载,使用setTimeout或setInterval进行加载延迟,如果用户在...
  • 2.采用懒加载:只加载可视区域的图片,即滚动到可视区域时再加载图片。 vue-lazyload-img:VUE图片懒加载插件 vue-progressive-image:VUE的渐进图像加载插件 二、渐进式加载 2.1 安装引入依赖 1.安装 npm...
  • URL输入到页面加载期间的性能优化总结。 从URL输入到页面显示,这期间具体发生了什么?并从中总结出可以优化页面加载速度的点。 DNS解析>
  • 前端优化图片加载## 一、什么事懒加载加载技术(简称lazyload)是对网页性能优化的一种方案。lazyload的核心是按需加载,避免网页打开时加载过多资源,让用户等待太久,在适当的时候加载用户需要的资源(这里...
  • 前言 一个网站的加载速度有多重要? 反正我相信之前来 博主网站 的人至少有 50% 在加载完成前关闭了本站。... 正常来讲一个网页 4s 加载不完就会流失很一部分用户,而博主的网站加载时间竟然达到...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,749
精华内容 8,299
关键字:

首页加载大图片优化