写在前面
最近一直处于空闲期,由于暂时没有工作压力,所以也不太想更一些技术博客(在非钻研时期强行写技术博客确实是一件比较无聊的事),就想着不如趁着有空给博客优化一下吧😑,没准能一劳永逸呢。然后就惊讶地发现...这工作还真的不简单,且容我慢慢道来。
现在主流的测速评分网站当属标题上提到的 Google PageSpeed Insights 了,这个是 Google 提供的检测工具,可以通过分析网页的内容提供网站加载速度优化建议,检测内容大概分为以下几个部分:
- 优化缓存:让你应用的数据和逻辑完全避免使用网络从而加速访问
- 减少回应时间:减少一连串请求-响应周期的数量
- 减小请求大小:减少上传大小
- 减小有效负荷大小:减小响应、下载和缓存页面的大小
- 优化浏览器渲染:改善浏览器的页面布局
然后我就对着评分报告优化了一天,结果就是从原来的 50 多分优化到 70 多分,然后由于使用了某种奇怪的操作又跌到了 60 多分,心情就像坐过山车一样😈,这个结果对我来说真的满(la)意(ji)的。
我的友链中已经有部分小伙伴的博客测速评分接近满分了,抛去🍋羡慕的因素,我仔细审视了一下差距,发现接近满分的绝大多数首页都比较「素」,或者说非常「简陋」的,当然这不是贬义,这更多是体现了做博客的审美观念不同,在我目前的审美观念中,确实很难为了提升分数去抛弃现有的外观。
另外一个原因,就是因为使用了 Google Fonts 托管的思源宋体😭,导致博客首次渲染超过 1s 以上的请求都是来自于字体加载,这个极大的拖慢了首次加载速度。
如何给博客提速
由于我的站点是基于 Java + FreeMarker 的动态博客,虽然 halo 框架在后台已经做了很多的优化,但是始终是比不上 Hexo、Hugo 等一系列静态框架的加载速度。如果你使用的是静态框架,在首页加载上略做优化超过 70 分应该是非常轻松的一件事。此外,由于我的博客使用了 Pjax,虽然可以保证整体浏览上比较迅速,但是所有需要用到的 js 文件必须放到公共 head 中加载或者在 Pjax 加载 complete 后进行动态嵌入,这导致 js 加载的十分集中,且无法将某个页面使用的局部 js 单独放到该页面中延迟加载。虽然可以使用 async 异步加载和 defer 延迟加载延缓一下,但是仍然解决不了根本问题,目前看来我对这个问题基本无解,所以这也是优化不上去的原因之一吧😒。
不过我折腾了一天多,也收获了一些提速方法,以下方法如果有误,还请在评论区指正😁。
图片懒加载
如果你的站点首页跟我的一样,每篇文章都带一张图,那么懒加载手段应该是必须要使用的,图片加载请求耗时是相对很长的,这极大的影响了首页的加载速度。当然首页没图的就不用看这条了(悄悄告诉你,首页没图的在 PageSpeed 上评分都很高哦😜)。很多博客框架实际上都自带了懒加载插件,一般还是不需要我们操心的,比如 Sakura 这种带图的主题都内置了懒加载。但由于我这个是自己改的首页模板(模仿 Sakura 主题),所以我需要自己使用懒加载插件。
开源懒加载插件在 Github 上提供了很多,我这里为了方便大家,就推荐一个傻瓜式的懒加载插件,它的名字就叫 lazyload,使用方法非常简单,我们只需要在博客需要使用图片懒加载的页面引入如下 js 文件:
//CDN的lazyload插件
<script src="https://cdn.jsdelivr.net/npm/lazyload@2.0.0-rc.2/lazyload.js"></script>
然后在对应的图片 <img>
标签内做出如下修改,就是把图片真实的 src
路径放入 data-src
中,并给 img
标签增加 class
为 lazyload
的属性, src
处不填时,默认初始加载时填充一张灰色的背景图,填写 src
时默认就加载你给定的图片,然后加载完成后会用 data-src
中的值替换 src
中的值实现懒加载的效果。
<img class="lazyload" data-src="img/example.jpg" width="765" height="574">
<img class="lazyload" src="img/example-thumb.jpg" data-src="img/example.jpg" width="765" height="574">
最后,在页面的 <script>
中还要加载一下这个插件,方式如下:
$("img.lazyload").lazyload();
注意使用懒加载时,最好在 <img>
标签中指定图片的 width
和 height
,这样页面在渲染时不用去计算图片的宽度和高度,而是能够直接响应,从而提升图片渲染速度。
图片压缩
图片压缩的重要性我在之前的博客中已经提到过,它的重要性是不言而喻的,除此之外,Google PageSpeed Insights 在测速报告中也给出了另外一个建议:
也就是采用新一代图片格式,给出的几个中使用相对广泛的应该是 WebP 格式,那么什么是 WebP 格式呢?
我们可以对比一下 WebP 图片的大小和其它格式图片的大小差异。
一般而言,WebP 格式的图片体积都较小,这更有利于网页速度的加载,但不是绝对的,如果原始图片很小(比如 10k、20k 左右),有时候转换成 WebP 反而体积会变大,这说明不是所有时候都需要使用 WebP。但是在一些固定的背景图片中,使用 WebP 格式图片无疑是一种更好的选择。
推荐几个在线转换 WebP 的网站:又拍云、智图、iSparta。
诚然,WebP 的确很优秀,但是也不是没有缺点,它最大的缺点应该就是兼容性不算优秀。但是能看到这篇博客的朋友们,至少使用的应该都是 Chrome、Firefox 或者 Safari 浏览器,而这些主流浏览器都已经支持了 WebP 格式图片,所以影响并不是很大。
保证字体始终可见
在 PageSpeed 给出的建议有这么一条:
我们知道,为了网站的文字排版丰富便于阅读,我们使用一些在线字体是难以避免的,而因为中文字体体积很大,为了避免网络阻塞一般都是拆分成很多个小文件再进行加载,这样虽然解决了字体下载的一些痛点,但是仍然难免会受到网络状况的影响,继而干扰用户的体验。说实话,如果连页面展示都费劲,谁还会在乎你用多炫的字体呢。
为了减轻字体因为下载慢而加载不出来的风险,大多数浏览器都采用了超时处理。一旦超时,就使用后备字体。理想很美好,现实很无奈,浏览器在实现上各有自己的一套。
- Chrome 和 Firefox 超时时间为 3 秒,超时后使用后备字体。若字体最终勉强加载成功,它将替换后备字体,重新渲染文本。
- IE 浏览器超时时间为 0 秒,也就是说,会立即渲染文本。若所请求的字体尚不可用,则使用后备字体。一旦请求字体可用,将重新渲染文本。
- Safari 没有超时行为(或者说,至少在基准网络超时之前什么也没干)。
更糟糕的是,这些规则对应用造成的影响,在很大程度上不受开发者控制。因此 CSS 工作组为此提出了新方案:为 @font-face
增加新的 font-display
声明,用于控制字体下载完成之前的渲染行为。与一些浏览器目前使用的字体超时行为类似,font-display
将字体下载过程划分为三个阶段。
-
首先是字体阻塞阶段(font block period)。在此期间,如果字体未完成加载,则尝试使用它的任何元素,必须以不可见的后备字体形式呈现;否则正常使用该字体。
-
紧接着字体阻塞阶段的是字体交换阶段(font swap period)。在此期间,如果字体未完成加载,则尝试使用它的任何元素,必须使用后备字体进行渲染;否则正常使用该字体。
-
紧接着是字体故障阶段(font failure period)。此时若字体未完成加载,则将其标记为下载失败,并使用常规后备字体;否则正常使用该字体。
理解以上三个阶段,根据字体是否下载成功、何时下载完成等情况,就可以使用 font-display
来决定如何渲染字体了。font-display
中可以选择如下属性:
- auto:默认值。典型的浏览器字体加载的行为会发生,也就是使用自定义字体的文本会先被隐藏,直到字体加载结束才会显示。
- swap:后备文本立即显示直到自定义字体加载完成后再使用自定义字体渲染文本。在大多数情况下,这就是我们所追求的效果。
- fallback:这个可以说是 auto 和 swap 的一种折中方式。需要使用自定义字体渲染的文本会在较短的时间(100ms according to Google)不可见,如果自定义字体还没有加载结束,那么就先加载无样式的文本。一旦自定义字体加载结束,那么文本就会被正确赋予样式。
- optional:效果和 fallback 几乎一样,都是先在极短的时间内文本不可见,然后再加载无样式的文本。不过 optional 选项可以让浏览器自由决定是否使用自定义字体,而这个决定很大程度上取决于浏览器的连接速度。如果速度很慢,那你的自定义字体可能就不会被使用。
举个例子:
@font-face {
font-family: "Open Sans Regular";
font-weight: 400;
font-style: normal;
src: url("fonts/OpenSans-Regular-BasicLatin.woff2") format("woff2");
font-display: swap;
}
在这个例子里我们通过只使用WOFF2文件来缩写字体。另外我们使用了swap作为font-display的值,页面的加载情况将如下图所示:
那后备文字是什么呢?当你给一个元素指定font-family时,你可以指定一系列的字体,并通过逗号来分隔这些字体。在自定义字体后的那些字体如果能得到浏览器的支持,那么这个字体就是后备字体
p {
font-family: "Open Sans Regular", "Helvetica", "Arial", sans-serif;
}
在上面这个例子中,自定义字体是 Open Sans Regular
,系统字体是 Helvetica
和 Arial
。当我们将 font-display
的值设置为 swap
的时候,最开始会先使用系统字体来显示文字,当自定义字体下载完毕后,自定义字体就会取代系统字体。当 font-display
的值设置为 fallback
和 optional
时,显示的字体将会取决于在决定如何处理自定义字体时系统堆栈中的后备字体是什么字体。
关于 CSS 和 JS 的优化
压缩 CSS 和 js 应该是最基本的方法,这个对网站加载速度的提升是巨大的,可以使用在线工具或者其它编辑器压缩插件完成压缩,除此之外,我们还需要注意一点小细节,就是在外部引入的 CSS 和 JS 的位置关系。
所谓外部引入,就是我们使用 <link rel="stylesheet" href="/xxx.min.css">
引入的 CSS 和 <script type="text/javascript" src="/xxx.min.js"></script>
引入的 JS 文件。
评论