文本的先统一讲一讲页面的优化,详讲图片优化、动画优化。

1. 优化

从首屏加载时间上来看,10%~20%的最终用户响应时间是花在从Web服务器获取HTML文档,并传送到浏览器中。而剩余的80%~90%的时间都花在了HTML文档所引用的所有组件(图片、脚本、样式表等)。所以优化这部分最重要。
对于首屏加载可以做的优化有:

  1. 减少http请求
    (1)使用CSS Sprites
    (2)使用内联图片,就是通过使用data:URL模式可以在Web页面中包含图片而无需任何额外的HTTP请求。
    (3)合并脚本、样式表,减少脚本和样式表的数量就减少HTTP请求。以合并脚本为例,不是要将所有的js都合并到一个文件中,而是需要保持js的模块化
    减少http请求的好处在哪儿呢?
    在HTTP1.1版本中有keep-alive的特性,当发送多个http请求,只会建立一次tcp连接。因此发送一次请求相比发送多次请求的优点主要体现在网络延迟上。
    网络延迟其实是在有keep-alive情况下仍然需要请求合并的主要动力。
    如果考虑丢包,合并请求更有优势。合并后的文件可以允许队首丢包之后在中间传输过程中补上来,而分开资源的时候,前一个资源未加载完成后面的资源内容是不能加载的,会有更严重的队首阻塞问题,所以丢包率能进一步影响keep-alive下多个小文件的传输。
    当然合并文件也有缺点。文件合并的越多,合并文件的缓存失效率就越高。
  2. 将静态资源比如:图片、脚本、样式表转移到CDN上。
    CDN是将源站资源分发至距离用户最近的节点,减少用户请求资源的时间,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载。
    CDN加速:
    CDN也会有缓存,当一个请求到达CDN,首先先检测缓存资源是否有效,如果有效,则立即响应缓存内容给用户,从而加快响应速度。如果CDN节点的缓存失效,它会根据服务配置去我们的内容源服务器获取最新的资源响应给用户,并将内容缓存下来以便响应给后续访问的用户。因此,一个地区内只要有一个用户先加载资源,在CDN中建立了缓存,该地区的其他后续用户都能因此而受益。
  3. 在服务器上配置使用缓存:expires和cache-control的max-age。
    当expires和cache-control的max-age没有过期,但是服务器上的资源改变了又应该怎么办呢?最有效的而解决方法就是修改资源链接的文件名。如果时间过期,则发送一个条件GET请求,如果资源没有变则服务器发送一个304的响应,告诉浏览器资源没有改变,并且重新设置expires和cache-control的max-age。
  4. 可以将html、样式表和脚本进行压缩。客户端通过HTTP请求中的Accept-Encodeing来标识对压缩的支持:
    Accept-Encodeing:gzip, default
    服务器通过响应中的Content-Encoding:gzip来通知客户端使用哪种压缩方法。
    压缩通常能将响应的数据量大大减少。
    压缩的配置取决于服务器的类型和版本。

2. 图片优化

如果将图像原始格式直接存储到文件中将会非常大,比如一个50005000 24位图,所占文件大小为50005000*3字节=71.5MB, 其大小非常可观。如果用zip或rar之类的通用算法来压缩像素数据,得到的压缩比例通常不会太高,因为这些压缩算法没有针对图像数据结构进行特殊处理。
于是就有了jpeg,png等格式,同样是图像压缩算法jpeg和png也有不同的适用场景,所以jpeg,png文件之于图像,就相当于zip,rar格式之于普通文件(用zip,rar格式对普通文件进行压缩)。
图片一般有三种格式:png、jpeg和bmp。
bmp:没有压缩像素格式。
jpeg:jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化。jpeg没有透明信息。jpeg比较适合用来存储相机拍出来的照片。
png:png是一种无损压缩格式,png可以有透明效果。png比较适合适量图,几何图。
jpeg比较适合存储色彩“杂乱”的拍摄图片,png比较适合存储几何特征强的图形类图片。
gif:上面提到的bmp,jpeg,png图片都只有一帧,而gif可以保存多帧图像。

  1. 使用CSS Sprites
    将小图片放在一张图片上进行传输,然后使用background-position定位到需要的图片上。雪碧图的优点是:可以减少http请求。缺点是:如果图片请求失败,雪碧图中的图片页面都无法加载。
  2. 使用css、svg、canvas或iconfont代替图片
  • svg:
    矢量图片,不受像素影响。支持透明,缩放,动画,除了android 2.3的手机,其它场景都支持,是一种比较好的图片代替方案。
    SVG的结构是 XML,其可访问性(盲文、声音朗读等)、可操作性、可编程性、可被CSS样式化完胜Canvas。另外,其支持 ARIA 属性,使其如虎添翼。
    SVG对动画的支持较好;其DOM结构可以被其特定语法或者Javascript控制,从而轻松的实现动画
    SVG功能更完善,适合静态图片展示,高保真文档查看和打印的应用场景。
    SVG不适合大量元素,但是适合屏幕大的。因为DOM比正常的图形慢,而且如果其结点多而杂,就更慢了。不适合网页游戏等
  • canvas:
    位图,Canvas提供的功能更原始,适合像素处理,动态渲染和大数据量绘制
    css代替图片:
    场景:适用于移动端或较高级的浏览器,而且绘制的图案较为简单。
    原理:css方式可以用来绘制相对简单的团来代替图片,一般使用before或者after伪元素来丰富图案的复杂度。
    优势:实现简单,可以实现简单的动态效果
    劣势:也受限于css的兼容性特点,绘制复杂图案困难
  1. 压缩图片
    优势:减少图片加载流量,效果比较明显 劣势:服务器和浏览器压力增大,而且服务器需要额外的服务支持,格式转换要考虑浏览器的兼容性

3. 动画优化

  1. 避免强制reflow
    浏览器是在下一帧、下一次渲染的时候才reflow,并不是JS执行完这一行改变样式的语句之后立即重排,所以你可以在JS语句里写100行改CSS的语句,但是只会在下一帧的时候重排一次。
    然而强制reflow会导致浏览器立刻reflow,因此要尽量避免强制reflow的操作。强制reflow主要有:clientWidth、offsetWidth、scrollWidth、getBoundingClientRect等。
  2. 将必要的动画提升至合成层,通过开启3D加速或使用will-change属性
    提升至合成层动画不需要重绘,只需要重新合成即可。这样动画的处理会很高效。
    will-change 的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用 will-change 会导致大量的内存占用。最佳实践是当元素变化之前和之后通过脚本来切换 will-change 的值。
  3. 避免隐式合成
    尽量让需要进行 CSS 动画的元素的 z-index 保持在页面最上方,避免浏览器创建不必要的合成层(GraphicsLayer),能够很好的提升渲染性能。
  4. 使用css动画
    css动画有一个重要的特性,它是完全工作在GPU上。因为你声明了一个动画如何开始和如何结束,浏览器会在动画开始前准备好所有需要的指令;并把它们发送给GPU。而如果使用js动画,浏览器必须计算每一帧的状态;为了保证平滑的动画,我们必须在浏览器主线程计算新状态;把它们发送给GPU至少60次每秒。除了计算和发送数据比css动画要慢,主线程的负载也会影响动画; 当主线程的计算任务过多时,会造成动画的延迟、卡顿。
  5. 尽量使用transform 代替 left、top,减少使用耗性能样式
    现代浏览器在完成以下四种属性的动画时,消耗成本较低:
    position(位置): transform: translate(npx, npx)
    scale(比例缩放):transform: scale(n)
    rotation(旋转) :transform: rotate(ndeg)
    opacity(透明度):opacity: 0…1
    如果可以,尽量只使用上述四种属性去控制动画。

4. 项目优化

  1. DNS预获取 dns-prefetch 提升页面载入速度
    当我们从该 URL 请求一个资源时,就不再需要等待 DNS 的解析过程。该技术对使用第三方资源特别有用。通过简单的一行代码就可以告知那些兼容的浏览器进行 DNS 预解析,这意味着当浏览器真正请求该域中的某个资源时,DNS 的解析就已经完成了,从而节省了宝贵的时间。
    另外需要注意的是,浏览器会对a标签的href自动启用DNS Prefetching,所以a标签里包含的域名不需要在head中手动设置link。但是在HTTPS下不起作用,需要meta来强制开启功能。这个限制的原因是防止窃听者根据DNS Prefetching推断显示在HTTPS页面中超链接的主机名。下面这句话作用是强制打开a标签域名解析
  2. JavaScript 模块打包
    使用Webpack模块打包,可以保持js的模块化,对于优化主要体现如下:
  • optimization.splitChunks
    将entry文件的公共引用模块提取出来,
    将node_modules提取到vendors中
  • 通过externals配置来提取常用库
    配置后可以告知webapck遇到此类变量名时就可以不用解析和编译至模块的内部文件中,而改用从外部变量中读取,这样能极大的提升编译速度,同时也能更好的利用CDN来实现缓存。
  • 使用Happypack加速你的代码构建
    Happypack的出发点就是,让可以并发执行的loader,加快构建。
  • uglifyJSPlugin
    压缩js代码
    使用webpack,保持模块化的同时,减少资源文件的加载,压缩代码,加快项目构建速度和减少http请求
  1. 按需加载资源
    图片懒加载