Web优化躬行记(1)——CSS
Web优化躬行记(2)——JavaScript
Web优化躬行记(3)——图像和网络
Web优化躬行记(4)——用户体验和工具
浏览器根据屏幕大小、设备像素比、横竖屏自动加载合适的图像。
响应式的功能可以通过srcset和sizes两个新属性实现。
前者可指定选择的图像以及其大小,后者会定义一组媒体条件并声明填充的宽度。
在下面的示例中(在线查看效果),浏览器会先查看设备宽度,然后检查sizes列表中哪个媒体条件第一个为真,再查看该媒体查询的填充宽度,最后从加载的srcset列表中引用宽度最接近的图像。
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" />
懒加载就是当滚动到页面某个位置后,再显示当前位置的图像,这样做可以减少页面请求。
预加载就是通过Image对象,给这个对象添加src属性,以JavaScript的方式请求图像,并可以缓存此对象,以后再用。
渐进加载是指先加载低质量甚至模糊的图片,然后随着页面继续加载,使用LQIP(低质量图片占位符)技术替换为高质量的完整版本。
这种技术确实提高了首次进行有意义绘制的时间。
除了可通过剥离元数据(例如时间、地点等)的方式压缩图像之外,还可以将图像画到Canvas中,然后选择质量输出,从而实现压缩。
CSS Sprite是一种图像处理技术,将零散的小图标整合在一起,形成成一张大图,这张图可称为雪碧图或精灵图。
当用这张大图做背景图像时,可以利用background-position属性进行背景定位,找到想要的小图标。
这么处理图像,不但可以解决命名困扰,还能减少HTTP请求数,降低图像字节,提升网页性能。
参照下面的最佳实践,可将雪碧图优化得尽可能小:
1. 按照颜色合并。
2. 避免不必要的空白。
3. 将元素水平排列。
4. 将颜色限制在256种以内。
5. 先优化单独的图像,再优化雪碧图。
6. 通过控制大小和对齐减少反锯齿像素的数量。
7. 避免使用对角线渐变,这种渐变无法被平铺。
WebP由Google引入,是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式VP8。
根据Google的测试,无损压缩后的WebP比PNG文件少了45%的文件大小,即使这些PNG文件经过其他压缩工具压缩之后,WebP还是可以减少28%的文件大小。
WebP不支持像JPEG那样的渐进式渲染,这导致用户使用好的JPEG可能会更快地看到实际图像,尽管WebP图像的网络加载速度可能会更快。
图标字体(icon font)就是将图标做成字体,使用时与普通字体无异。
换成字体后,颜色、阴影、翻转、大小和对齐等功能都能用CSS属性控制,比图像灵活很多,并且缩放还不会失真,同时兼容IE6,并且生成的文件特别小。
使用font-display这个CSS属性来控制字体的加载行为并使内容立即(font-display: optional)或几乎立即(font-display: swap)可读。
字体加载API用JavaScript来控制如何加载字体,提供了很大的自由度来决定如何将字体应用于文档。
document.fonts.load("1em Open Sans Light"); //加载字体
document.fonts.load("1em Open Sans Bold");
// 在所有指定的字体都加载后运行
document.fonts.ready.then(function(fontFaceSet) { });
通过添加HTTP首部来向Web服务器声明支持压缩。
Accept-Encoding: gzip, deflate
Web服务器会返回一个经过压缩的响应。
Content-Encoding: gzip
GZip对于要压缩的文件,首先使用LZ77算法,然后对得到的结果再使用Huffman编码的方法进行压缩。
LZ77算法过程如下:
1. 如果文件中有两块内容相同的话,那么只要知道前一块的位置和大小,就可以确定后一块的内容。
2. 可以用这样一对信息(两者之间的距离,相同内容的长度),来替换后一块内容。
3. 由于这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
Huffman编码过程如下:
1. 把文件中一定位长的值看作是符号,例如把8位长的256种值,也就是字节的256种值看作是符号。
2. 根据这些符号在文件中出现的频率,对这些符号重新编码。
3. 对于出现次数非常多的,用较少的位来表示,对于出现次数非常少的,用较多的位来表示。
4. 这样一来,文件的一些部分位数变少了,一些部分位数变多了。
5. 由于变小的部分比变大的部分多,所以整个文件的大小还是会减小,文件得到了压缩。
2015年,Google推出了Brotli,这是一种全新的开源无损数据格式,并被现在所有现代浏览器支持。
尽管Brotli在某些方面的性能与GZip相当,但它显示出了良好的前景,并在不断地发展中。
如果浏览器支持Brotli,那么在请求首部中会将br令牌包含在可接受的编码列表中。
Accept-Encoding: gzip, deflate, br
GZip的压缩级别可指定0~9的整数来配置,而Brotli的范围是0~11。
注意,使用Brotli压缩所有资源非常耗费计算资源和时间,在最高压缩级别下,会让服务器等待动态资源,服务器开始发送响应所花费的时间会抵消文件大小减少带来的任何潜在收益。
如果可以避开动态压缩静态资源的成本,那么Brotli就是值得的。
Brotli可用于任何纯文本的内容(HTML、CSS、SVG、JavaScript等),并且其性能相比GZip提高了17-25%。
DNS预读取技术能够加快打开速度,方法是在head元素里写上几个link元素。
<link rel="dns-prefetch" href="http://www.pwstrick.com">
<link rel="dns-prefetch" href="http://www.home602.com">
对以上几个网站提前解析DNS,由于是并行的,也就不会阻塞页面渲染。
缓存的处理过程可以简单的分为几步,首先在缓存中搜索指定资源的副本,如果命中就执行第二步;第二步就是对资源副本进行新鲜度检测(也就是文档是否过期),如果不新鲜就执行第三步;第三步是与服务器进行再验证,验证通过(即没有过期)就更新资源副本的新鲜度,再返回这个资源副本(此时的响应状态码为“304 Not Modified”),不通过就从服务器返回资源,再将最新资源的副本放入缓存中。
HTTP缓存分为强缓存和协商缓存,前者的首部包括Cache-Control和Expires;后者会分为日期比对法(If-Modified-Since和Last-Modified)和实体标记法(If-None-Match和ETag)。
CDN是在用户和服务器之间增加Cache层,将用户的访问请求引导到Cache节点而不是服务器源站点,要实现这一目的,主要是通过接管DNS实现。
CDN可以在全球分发各类资源,并根据地理位置、接入网类型(电信还是网通)将用户的访问请求定位到离用户路由最短、位置最近、负载最轻的Cache节点(缓存服务器)上,实现就近定位,以此提升性能。
浏览器的并发请求数目限制是针对同一域名的。
同一时间针对同一域名下的请求有一定数量限制(例如Chrome限制6条、IE11限制13条等),超过限制数目的请求会被阻塞。
所以将不同静态资源(例如图片、JavaScript、CSS等)放在不同的域名下,就能增加并发请求的数量。
HTTP/2.0引入了全新的二进制分帧层,解决了队首阻塞问题,并且在一个域只需建立一次TCP连接,就能实现多路通信,不必进行资源排队,这样就不需要雪碧图或合并文件了。
不仅如此,HTTP/2.0还有控制请求优先级、服务器主动推送和首部压缩等优点,
在设计和开发API时,需要一个合理的协议来实现服务器与第三方请求之间的通信。
Restful API(REST)是一种广泛验证有效的选择:它定义了一组约束,开发人员可以遵循这些约束以使内容以高性能,可靠和可伸缩的方式进行访问。符合REST约束定义的Web服务称为RESTful Web服务。
与普通的HTTP请求一样,当从API检索数据时,服务器响应中的任何延迟都将传播到最终用户,从而影响渲染。如果许多资源都需要来自某个API的数据,则该API可能会成为性能瓶颈。GraphQL为这些问题提供了高性能的解决方案。
与REST不同,GraphQL可以在单个请求中检索所有数据,并且只响应所需的内容,而不会像REST通常那样过度或不足地获取数据。
此外,因为GraphQL使用模式(Schema,定义数据结构的元数据),所以它可以提前将数据组织成所需的结构。因此在使用GraphQL后,就可以删除用于处理状态和数据结果的JavaScript代码,从而产生在客户端上运行更快更干净的应用程序代码。
把那些能阻塞网页首次渲染的资源称为关键资源,例如首次请求的 JavaScript、HTML和CSS等。
基于关键资源可细化出三个优化页面首次渲染的原则。
1. 第一个是减少关键资源个数。
2. 第二个是降低关键资源大小。
3. 第三个是减少请求关键资源的 RTT 次数。
RTT(Round Trip Time)就是往返时间,即数据发送时刻到接收到确认时刻的差值。