要解决的问题

对于项目中的图片,为了优化图片的加载速度,我们希望在不影响页面加载的情况下,减少图片的请求次数。比如多个svg可以通过一次请求得到,然后用前端处理获取想要的svg,因为一个svg只有2-5kb,不同svg都要走请求会增大网络请求压力,这里我将对此现象进行调研,并给出一个切实可行的方案。

1. base64编码

链接
使用场景:如果图片足够小且因为用处的特殊性无法被制作成雪碧图(CssSprites),在整个网站的复用性很高且基本不会被更新
比如:重复使用的小格子背景图。

CssSprites与Base64编码  
简单陈述一下我对何时这使用这两种优化方法的看法。
使用CssSprites合并为一张大图:

  • 页面具有多种风格,需要换肤功能,可使用CssSprites
  • 网站已经趋于完美,不会再三天两头的改动(例如button大小、颜色等)
  • 使用时无需重复图形内容
  • 没有 Base64 编码成本,降低图片更新的维护难度。(但注意 Sprites 同时修改 css 和图片某些时候可能造成负担)
  • 不会增加 CSS 文件体积

使用base64直接把图片编码成字符串写入CSS文件:

  • 无额外请求
  • 对于极小或者极简单图片
  • 可像单独图片一样使用,比如背景图片重复使用等
  • 没有跨域问题,无需考虑缓存、文件头或者cookies问题

在 chrome 下新建一个窗口,然后把要转化的图片直接拖入浏览器,打开控制台,点 Source,如下图所示,点击图片,右侧就会显示该图片的 base64 编码,是不是很方便。
雪碧图Sprite调查方案 - 图1

缺点:增大css体积,阻止关键路径渲染

基于这个思路,不妨考虑svg的问题,在html中直接写出svg可以避免对svg的网络请求,但是这种做法对于多次使用的svg并非合理,原因是svg在html占用一定体积,可复用的svg如果都写在html中,徒然增大了html的体积,会得不偿失。

因此,我认为分为两种:

  1. 对于少量引用或者单次引用的svg,如果体积不是非常大,可以直接写在html中;
  2. 对于多次,多处使用的svg,应当以网络请求形式请求svg。这里又存在一种优化形式,即使用雪碧图的优化,将类似于icon的svg使用cssSprite进行引用,这样可以有效减少网络请求。这一方法其缺点如前述,不好维护,一个svg变更后需要重新生成sprites,因此我们在开发阶段这里分模块使用不同sprites,最后统一使用一个雪碧图,这一点还有待验证。

2. sprites雪碧图

通过webpack实现雪碧图,需要在css中对所有icon进行处理,需要记录相应路径,封装性和可读性较差。

  • photoShop拼图
  • TexturePacker打包

3. svg代码优化

链接
原始svg

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
  3. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  4. <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174" xml:space="preserve">
  5. <g>
  6. <g>
  7. <ellipse id="shading" fill="#C6C6C6" cx="283.5" cy="487.5" rx="259" ry="80"/>
  8. <path id="bird" d="M210.333, 65.331C104.367,66.105-12.349, 150.637, 1.056, 276.449c4.303, 40.393, 18.533, 63.704… fill=”#000000"/>
  9. </g>
  10. </g>
  11. </svg>

There are several improvements we can make to the existing code:

  • Remove any unnecessary comments 评论删除
  • Delete the xml prolog and doctype 删除xml基础外层标签
  • Remove the SVG version,id, xlink (if unused), x, y, width andheight, enable-background, and any namespaced attributes. 删除id或namespace等可省略的内容
  • Remove any unneeded groups 删除group(无用的)
  • Simplify colors to hex shortcuts 简化颜色 简化精度
  • Remove extra spaces and carriage returns from the code 删除无用的换行

修改后svg

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 65 612 502">
    <ellipse fill="#C6C6C6" cx="283" cy="487" rx="259" ry="80"/>
    <path d="M210.333, 65.331C104.367, 66.105-12.349, 150.637, 1.056,276.449c4.303, 40.393,18.533, 63.704,52.171, 79.03 c36.307” … fill=”#000"/>
</svg>

These changes make several assumptions:

  • The width and height of the SVG illustration will be determined by CSS on the webpage. 宽高由css提供
  • xlink is not being used (ie, there are no linked elements).
  • Groups are not being used for any particular purpose: there are no transforms moving collections of objects, for example. xlink和group未被使用

4. SVG Sprites技术介绍

链接
非常好的文章,看完之后茅塞顿开

具体拟定技术方案为 准备好合成的svg,放入html顶端(或者通过请求引用),然后直接使用use进行使用,也以此避免多次的无用使用

例子
转换工具

5. 优化战报页面svg举例

我将以战报页面的优化作为例子。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="矩形" viewBox="0 0 716 211">
    <defs>
      <path id="b1" d="M0 0h716v211H0z" />
      <filter x="-2.8%" y="-4.4%" width="105.6%" height="108.7%" filterUnits="objectBoundingBox" id="a1">
        <feGaussianBlur stdDeviation="20" in="SourceAlpha" result="shadowBlurInner1" />
        <feOffset in="shadowBlurInner1" result="shadowOffsetInner1" />
        <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1" />
        <feColorMatrix values="0 0 0 0 0.0509803922 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" in="shadowInnerInner1" />
      </filter>
    </defs>
    <use filter="url(#a1)" xlink:href="#b1" fill-rule="evenodd" />
  </symbol>
  <symbol id="本场明星商品底">
    <path d="M165 2812h8v30h-8v-30zm12 0h8v30h-8v-30zm388 0h8v30h-8v-30zm12 0h8v30h-8v-30z" transform="translate(-43.375 -2795)" />
    <path d="M29.625 47l10-16h88m407 0h82l10 16" stroke="currentColor" stroke-width="2" fill="none" fill-rule="evenodd" />
    <path
      d="M670.268 2826l1.732-1 8.5 14.72-1.732 1zm10 0l1.732-1 8.5 14.72-1.732 1zm10 0l1.732-1 8.5 14.72-1.732 1zm-616.668-.01l-1.733-1-8.494 14.73 1.732 1zm-10 .01l-1.733-1-8.494 14.72 1.732 1zm-10 0l-1.733-1-8.494 14.73 1.732 1z"
      transform="translate(-43.375 -2795)"
    />
    <path id="标题底" d="M555 2795H215l-20 20v45h340l20-19.98V2795z" transform="translate(-43.375 -2795)" />
  </symbol>
  <symbol id="边框阴影" viewBox="0 0 720 459">
    <defs>
      <path id="b2" d="M0 0h720v459H0z" />
      <filter x="-2.8%" y="-4.4%" width="105.6%" height="108.7%" filterUnits="objectBoundingBox" id="a2">
        <feGaussianBlur stdDeviation="20" in="SourceAlpha" result="shadowBlurInner1" />
        <feOffset in="shadowBlurInner1" result="shadowOffsetInner1" />
        <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1" />
        <feColorMatrix values="0 0 0 0 0.0509803922 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" in="shadowInnerInner1" />
      </filter>
    </defs>
    <use filter="url(#a2)" xlink:href="#b2" fill-rule="evenodd" />
  </symbol>
  <symbol id="单排字底" null>
    <path d="M29.625 47l10-16h118m347 0h112l10 16" fill="none" stroke="currentColor" stroke-width="2" />
    <path d="M195 1892h8v30h-8v-30zm12 0h8v30h-8v-30zm328 0h8v30h-8v-30zm12 0h8v30h-8v-30z" transform="translate(-43.375 -1875)" />
    <path
      d="M670.268 1906l1.732-1 8.5 14.72-1.732 1zm10 0l1.732-1 8.5 14.72-1.732 1zm10 0l1.732-1 8.5 14.72-1.732 1zm-616.668-.01l-1.733-1-8.494 14.73 1.732 1zm-10 .01l-1.733-1-8.494 14.72 1.732 1zm-10 0l-1.733-1-8.494 14.73 1.732 1z"
      transform="translate(-43.375 -1875)"
    />
    <path id="标题底" d="M525 1875H245l-20 20v45h280l20-19.98V1875z" transform="translate(-43.375 -1875)" />
  </symbol>
  <symbol id="红阴影" viewBox="0 0 720 459">
    <defs>
      <path id="b3" d="M0 0h720v459H0z" />
      <filter x="-2.8%" y="-4.4%" width="105.6%" height="108.7%" filterUnits="objectBoundingBox" id="a3">
        <feGaussianBlur stdDeviation="20" in="SourceAlpha" result="shadowBlurInner1" />
        <feOffset in="shadowBlurInner1" result="shadowOffsetInner1" />
        <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1" />
        <feColorMatrix values="0 0 0 0 0.996078431 0 0 0 0 0.141176471 0 0 0 0 0.454901961 0 0 0 0.5 0" in="shadowInnerInner1" />
      </filter>
    </defs>
    <use filter="url(#a3)" xlink:href="#b3" fill-rule="nonzero" />
  </symbol>
  <symbol id="角标" viewBox="0 0 56 36">
    <path d="M47 31V9H5L1 1h54v34z" stroke="currentColor" stroke-width="2" fill-rule="evenodd" />
  </symbol>
  <symbol id="双排字底" viewBox="0 0 657 125">
    <path fill-rule="evenodd" d="M571 1422H199l-20 20v105h372l20-19.98V1422z" transform="translate(-43 -1422)" />
    <path
      fill-rule="evenodd"
      d="M148.594 1466h8v30.47h-8V1466zm12 0h8v30.47h-8V1466zm419.937 0h8v30.47h-8V1466zm12 0h8v30.47h-8V1466z"
      transform="translate(-43 -1422)"
    />
    <path
      d="M29.619 74.46l10-16.25H111.6m438.934 0h65.979l10 16.25"
      stroke="currentColor"
      fill="none"
      stroke-width="2"
      fill-rule="evenodd"
    />
    <path
      d="M669.774 1480.21l1.731-1.01 8.5 14.95-1.732 1.01zm10 0l1.732-1.01 8.5 14.95-1.732 1.01zm10 0l1.732-1.01 8.5 14.95-1.732 1.01zm-616.546 0l-1.732-1.02L63 1494.15l1.732 1.01zm-10 0l-1.732-1.01L53 1494.15l1.732 1.01zm-10 .01l-1.728-1.02-8.5 14.95 1.732 1.02z"
      transform="translate(-43 -1422)"
    />
  </symbol>
</svg>

<svg><use xlink:href="#角标" /></svg>
<svg width="657.125" height="65" fill="currentColor" fill-rule="evenodd"><use xlink:href="#单排字底" /></svg>

在顶部样式中,应该注意删除样式原本的颜色,然后svg应当增加fill=”currentColor”属性,增加宽高,宽高写在css内应当增加px。

6. cssSprite

对于某些特殊情况,图片大小一致,可以使用雪碧图。
使用工具生成,然后加载css即可。然后压缩对应png。