前言
最近刚刚使用Next.js重新写了企业的网站,由于Vercel的服务器很给力,并没有做什么优化处理,今天心血来潮打算对图片加载进行下优化,因为现在SEO优化中,网页加载速度也是一个考核项目,而且考虑到手机用户的流量问题,对图片大小进行优化还是很有必要的。
之前我的优化思路都是企图使用JavaScript的方法进行动态判断,但是这种方法有两个缺点,分别暴露在服务器端和客户端。
服务器端缺点
在服务器端根据浏览器的user-agent和header信息可以非常简单的判断浏览器能够支持哪些图片格式,然后生成静态的HTML信息。
但是这样一来就要从SSG模式退化到SSR模式,我的企业站目前访问量不高,这就有一个问题,那就是Serverless Function冷启动,Vercel为了节约服务器资源不可能给所有的网站提供24小时的服务器资源开销,当没有任何请求的时候,Vercel会关闭不使用的服务器资源,直到下一次用户请求再重新开启。如此一来就会发生页面启动很慢的情况,这样还不如不优化。
浏览器端的缺点
浏览器端用JavaScript来判断浏览器并发出相应的请求是可以避免SSR退化的问题,但是实现起来有点复杂,要么引进第三方库,要么自己手动实现,这些还要涉及到DOM操作等等,为了优化图片的加载,导致引入更多的麻烦,好像得不偿失啊。
最后我只能再次尝试使用<picture>,这个现代浏览器都支持的新标准了。
新标准的使用
<picture>已经成为了广泛使用的浏览器标准,之前我也尝试过使用它来实现图片的优化加载,但是被它的说明文档所迷惑,使用有一种琢磨不透的感觉,因此也就弃之不用了。现在想来可能是被<video>和<audio>这两个标签给误导所致。
<video>和<audio>的误导
<video>和<audio>是视频和音频媒体元素标签,而<picture>因为是图像资源,我自然而然的就拿去和这两个标签使用做比较。
但是<video>和<audio>这两个标签与<picture>的区别有点大。前者可以添加属性,然而后者什么属性都没有;这就令我很迷惑了,那么我该如何设置<picture>的宽度和高度呢?如何给图片设置样式呢?图片的交互怎么做呢?
最令我迷惑的是文档中的表述
HTML
<picture>元素通过包含零或多个<source>元素和一个<img>元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子<source>元素,如果没有匹配的,就选择<img>元素的src属性中的 URL。然后,所选图像呈现在元素占据的空间中。
看起来<img>好像是<picture>里面的一个必要自元素,是当所有<source>子元素中找不到匹配的图片资源才会用到<img>中的src作为<picture>的资源地址。
感觉上<img>应该是附属于<picture>才对,然而实际上文档最后轻描淡写的一句才是重点,<picture>会占据<img>的空间。
换个角度来看,<picture>与<img>的关系不是包含,应该是<picture>是<img>的拓展!<picture>起到的作用仅仅是给<img>提供更多的描述属性,这些属性由<source>子元素提供,<picture>相当于一个虚元素,它不会影响到排版布局,它与<video>和<audio>是完全不同的元素标签!
经过这番思考之后,我领悟到了<picture>的正确使用方法,接下来就可以对图片加载进行优化了。
图片优化
准备各种格式的图片资源
优化图片首先入手的就是准备各种格式的图片,网络上用的最多的格式是jpg,png和gif,这些格式有什么优缺点我就不再赘述了,做前端的应该都清楚了。
要准的图片格式当然是现在最新最流行的webp和avif图片格式了,现在的图片编辑软件应该都能输出webp格式的图片了,至于avif好像还需要第三方工具转换,反正我长使用的pixelmator pro暂时还不支持avif的图片格式输出。
使用webp格式输出的图片能够缩小到几乎一半都不到的大小,这对于移动网络来说实在是太好了。
准备不同大小的图片资源
由于手机这种便携式设备屏幕大小的缘故,我们可以使用小尺寸的图片来展示,虽然手机分辨率很高,但是人眼的分辨率只有那么点,所以小图片在手机上看起来还是很清楚的。而且使用<picture>可以动态的在不同分辨率之间加载不同大小的图片资源。
在使用新的图片格式和更小的图片尺寸后,我们可以使用原图十分之一都不到的文件大小就能呈现出不错的图片来了。
后续的会补上示例代码与大家分享,也可以先看看我优化后的网站效果