要解决的问题
对于项目中的图片,为了优化图片的加载速度,我们希望在不影响页面加载的情况下,减少图片的请求次数。比如多个svg可以通过一次请求得到,然后用前端处理获取想要的svg,因为一个svg只有2-5kb,不同svg都要走请求会增大网络请求压力,这里我将对此现象进行调研,并给出一个切实可行的方案。
1. base64编码
链接
使用场景:如果图片足够小且因为用处的特殊性无法被制作成雪碧图(CssSprites),在整个网站的复用性很高且基本不会被更新。
比如:重复使用的小格子背景图。
CssSprites与Base64编码
简单陈述一下我对何时这使用这两种优化方法的看法。
使用CssSprites合并为一张大图:
- 页面具有多种风格,需要换肤功能,可使用CssSprites
- 网站已经趋于完美,不会再三天两头的改动(例如button大小、颜色等)
- 使用时无需重复图形内容
- 没有 Base64 编码成本,降低图片更新的维护难度。(但注意 Sprites 同时修改 css 和图片某些时候可能造成负担)
- 不会增加 CSS 文件体积
使用base64直接把图片编码成字符串写入CSS文件:
- 无额外请求
- 对于极小或者极简单图片
- 可像单独图片一样使用,比如背景图片重复使用等
- 没有跨域问题,无需考虑缓存、文件头或者cookies问题
在 chrome 下新建一个窗口,然后把要转化的图片直接拖入浏览器,打开控制台,点 Source,如下图所示,点击图片,右侧就会显示该图片的 base64 编码,是不是很方便。
缺点:增大css体积,阻止关键路径渲染
基于这个思路,不妨考虑svg的问题,在html中直接写出svg可以避免对svg的网络请求,但是这种做法对于多次使用的svg并非合理,原因是svg在html占用一定体积,可复用的svg如果都写在html中,徒然增大了html的体积,会得不偿失。
因此,我认为分为两种:
- 对于少量引用或者单次引用的svg,如果体积不是非常大,可以直接写在html中;
- 对于多次,多处使用的svg,应当以网络请求形式请求svg。这里又存在一种优化形式,即使用雪碧图的优化,将类似于icon的svg使用cssSprite进行引用,这样可以有效减少网络请求。这一方法其缺点如前述,不好维护,一个svg变更后需要重新生成sprites,因此我们在开发阶段这里分模块使用不同sprites,最后统一使用一个雪碧图,这一点还有待验证。
2. sprites雪碧图
通过webpack实现雪碧图,需要在css中对所有icon进行处理,需要记录相应路径,封装性和可读性较差。
- photoShop拼图
- TexturePacker打包
3. svg代码优化
链接
原始svg
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<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">
<g>
<g>
<ellipse id="shading" fill="#C6C6C6" cx="283.5" cy="487.5" rx="259" ry="80"/>
<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"/>
</g>
</g>
</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
andheight
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。