少女祈祷中...

网页性能优化是一个很重要的话题。根据Google的研究,网页加载时间超过3秒时,用户会离开网页。因此,尽可能地减少网页加载时间,提高用户体验是非常重要的。

以我的博客为例,我使用的是 hexo 框架,主题是自己开发的 hexo-theme-reimu。在 hexo-theme-reimu v0.1 版本中,使用 lighthouse 进行 PC 和 Mobile 的性能测试,得分如下:

v0.1

而虽然随着时间推移,博客功能越来越丰富,但是性能却在不断提升。在 v0.3 版本中,得分已经升到了:

v0.3

本文将以此为例,介绍我是如何优化博客性能的,希望对大家有所帮助。

CSS/JS 优化

替换过时依赖

许多的博客都会使用 fancybox 来实现图片的放大功能。但是由于协议问题(高版本不再使用 MIT 协议),我们只能使用 fancybox v3 版本。而这个版本的 fancybox 已经过时,不再维护。且其本身是依赖 jQuery 的,而 jQuery 本身也是一个庞大的库。因此,我们可以考虑使用 PhotoSwipe 来替代 fancybox。相比 fancybox,PhotoSwipe 更加轻量,体积从 31.8KB(jQuery) + 22.7KB(fancybox) + 3.5KB(css) 变为 4.9KB(PhotoSwipe-lightbox) + 16.8KB(PhotoSwipe,懒加载) + 2.7KB(css)。

延迟加载无关资源

事实上,虽然 reimu 本身提供了诸如 mermaid 这样强大功能,但是并不是所有文章都需要这些功能。例如,在首页上,我们只需要文章的标题、摘要和封面图,而不需要 katex 和 mermaid。因此,我们可以将 mermaid 的加载延迟到文章页。从而减少首页的加载时间。

所以,我们可以在文章页的模板中,判断是否需要加载 mermaid,如果需要,则加载对应的资源:

1
2
3
<% if (theme.mermaid.enable && page.mermaid) { %>
<%- js({src: vendorCdn(theme.vendor.js.mermaid)[0], 'data-pjax': true}) %>
<% } %>

异步加载低优先级资源

资源也有高优和低优之分。像是字体、图标、进度条等资源属于高优资源,其应该尽快加载;而像是评论、统计、搜索等功能所对应的资源属于低优资源,其可以延迟加载。

对于 css,可以使用 rel="preload" 属性,使其异步加载,防止阻塞渲染:

1
<link rel="preload" href="" as="style" onload="this.onload=null;this.rel='stylesheet'">

对于 js,可以使用 asyncdefer 属性,使其异步加载,防止阻塞渲染:

1
2
<script src="" async></script>
<script src="" defer></script>

字体/图标优化

iconfont VS fontawesome

fontawesome 提供了非常丰富的图标,但是其体积也非常庞大。假如我们只需要其中的几个图标,但其分布在 fontawesome 的 brand、solid、regular 等多个字体文件中,这样就会导致我们不得不加载整个 fontawesome。而 iconfont 则可以根据我们的需求,选择性地下载我们需要的图标,从而减少字体文件的体积。

以 reimu 为例,v0.1 版本中使用的是 fontawesome,需要加载 regular.min.csssolid.min.cssbrands.min.css 这 3 个 css 文件以及对应的 woff2 字体文件。而在 v0.3 版本中,使用的是 iconfont,只需要加载 iconfont.cssiconfont.woff2 这 2 个文件,请求次数和体积都大大减少。

Font css 优化

字体文件的加载也是一个很重要的问题。字体文件的加载会阻塞渲染,因此我们需要尽快加载字体文件。但是,如果我们直接使用 @font-face 来加载字体文件,那么字体文件会在 css 加载完毕后才开始加载,这样就会导致字体文件的加载延迟。因此,我们可以使用 preconnectpreload 来提前加载字体文件:

1
2
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css/xxxx">

对于 css 中使用的 iconfont 字体文件,我们也可以对其进行预加载:

1
<link rel="preload" href="//at.alicdn.com/t/c/font_xxxx.woff2" as="font" type="font/woff2" crossorigin="anonymous">

图片优化

图片懒加载

老生常谈的话题,使用 lazysizeslozad.js 等库来实现图片懒加载。这样可以减少首页的加载时间,提高用户体验。

webp VS jpg

强烈建议使用 webp 格式的图片。webp 格式的图片体积更小,加载速度更快。根据 caniuse 的数据,webp 格式的图片在现代浏览器中都有很好的支持。

如果需要使用 png 格式的图片,建议使用 tinypng 来压缩图片。tinypng 是一个非常好用的图片压缩工具,可以将图片的体积减小 50% 以上。

善用 srcset

srcset 是一个非常好用的属性,可以根据设备的分辨率,选择合适的图片。将其使用在封面大图上,并配合上 fetchpriority="high",可以提高移动端的加载速度。

1
2
3
4
5
6
7
8
9
10
<% if (theme.banner_srcset.enable) { %>
<picture>
<% for (var i of theme.banner_srcset.srcset) { %>
<source media="<%= i.media %>" srcset="<%- url_for(i.src, {relative: false}) %>">
<% } %>
<img fetchpriority="high" src="<%- url_for(theme.banner, {relative: false}) %>" alt="<%= post.title %>">
</picture>
<% } else { %>
<img fetchpriority="high" src="<%- url_for(theme.banner, {relative: false}) %>" alt="<%= post.title %>">
<% } %>