博客重构记录
重构博客网站,也就是该网站的记录。
多用 CSS
近期订阅了一些英语的周刊,主要是前端相关,里面收集了很多外网博客平台上的优秀文章。其中不乏有一篇文章吸引到了我:很多时候你根本不需要使用 JavaScript。
吸引我的理由很简单。我的前端技术栈主要是 React.JS。相较于传统的「网页三剑客」,React.JS 这类现代前端框架需要客户端下载并执行更多的 JavaScript 代码。其核心的虚拟 DOM 技术虽然在过去带来了性能优势,但在现代浏览器性能已大幅提升的今天,其初始化和运行时成本有时反而不如原生方法来得直接高效。
但是,对过去的我而言,功能就是要用 JavaScript 才能做到。纯 HTML 和 CSS 能做到什么?它们又不是脚本语言。 不过在那个文章里,这个想法是片面的。现代的 CSS 技术进化很快、有着性能优异的各类方法,完全可以代替 JavaScript 来实现一些功能。
举个例子,我们想要实现主题切换功能。
如果是网页三剑客的话,我们可能会想到用 JavaScript 监听切换按钮,该按钮被点击了我们就改变被监听的类或者元素的样式。
在 React.JS 上的话,那就是存一个主题状态:如果是 light 模式就怎么怎么样;如果是 dark 模式就怎么怎么样。如果用的还是 Material-UI 或者其他 UI 框架,那大概率还会有个 theme 配置文件。
这些方案对我们而言应该都很熟悉:对啊,怎么了,这样做不是很正常吗。
其实可以更简单一些,用 CSS 的
color-mix()
方法就可以办到: scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 :root {
// 核心品牌色
--color-primary: #5454f8;
--color-secondary: #267B54;
--color-accent: #4088b8;
// 使用 color-mix() 生成交互状态
--color-primary-hover: color-mix(in srgb, var(--color-primary) 85%, black);
--color-secondary-hover: color-mix(in srgb, var(--color-secondary) 85%, black);
--surface-interactive-hover: color-mix(in srgb, var(--surface-interactive) 80%, var(--color-primary));
}
// 深色主题
[data-theme="dark"] {
--color-primary: #818cf8;
--color-secondary: #34d399;
--color-accent: #60a5fa;
// 深色模式下的交互状态
--color-primary-hover: color-mix(in srgb, var(--color-primary) 80%, white);
--color-secondary-hover: color-mix(in srgb, var(--color-secondary) 80%, white);
--surface-interactive-hover: color-mix(in srgb, var(--surface-interactive) 70%, var(--color-primary));
}又或者,我们想要创建模态框。通常我们会写一个
<div>
,然后写 JavaScript 来控制它的显示和隐藏、背景遮罩、锁定用户的键盘焦点、处理Esc
键退出等等等等。实际上,可以直接用<dialog>
来写、用::backdrop
伪元素给背景遮罩添加样式和动画、用@starting-style
来实现更流畅的入场动画。其他交互效果,例如按钮的颜色变化就更不用说了。这里还有一个很有意思的考量:JavaScript 很可能带来安全问题,而 CSS 是完全安全的。
带着这些全新的知识点,我重构了我的博客网站。其实之前我对于网站设计是没有一丝考量的,也不在乎 CSS 这些让我觉得「不如 React.JS 优雅高级」的技术,因此我的博客网站性能一般,对比原本主题的设计还添加了许多非必需的东西。我的顶部菜单栏出现过明显的元素堆积过多的情况,一些按钮很丑很奇怪、像是四不像、哪儿哪儿都不挨上,所以我决定先在博客网站上将部分功能撤下。其中就有搜索功能:首先它的样式我一直没有设计、难看得很;其次是这个功能我认为没必要留、不够精简。未来如果需要的话,我会想一个更好的方案。
不过在 Hexo Theme Ares 里,搜索功能还会保留,并且进行了一次小重构。
我还撤走了评论区的 Disqus 评论区,因为这东西多多少少会给我带来一些影响:今天有没有人发评论?今天有没有人作反应? 其实很没必要,本身看的人就不多。
字体
正确导入字体
我不只是将一些功能用 CSS 重构了,我还改了一下字体的导入方式,参考的是另一篇 优质的文章,具体讲了现代网站是如何错误地导入字体的。
我的博客主题原先会导入足足四个字体:
- 英语的 Open Sans
- 简体中文的 Noto Sans(其实就是思源黑体,不过我在考虑换成其他的;我个人阅读时喜欢用霞鹜文楷,但还没尝试换过,有可能和我的主题不搭配)
- 用于特殊标题的 Dosis
- 代码块用的 JetBrains Mono
这些字体都是用 Google Fonts 的 CDN 导入的。其实这种方式并非最佳实践,很容易导致性能问题:浏览器会发起两次请求,第一次用于请求 fonts.googleapis.com
这个地址、获取一个 CSS 文件,第二次则是请求 CSS 文件内的真实字体文件地址。这个过程至少会有两次网络往返,第一次请求的 CSS 文件会阻塞渲染,这意味着在它下载完成之前,页面可能是一片空白或者没有应用任何样式。为了解决这些问题,我是这么做的:
1 | // 1. 加载真正的 Open Sans 字体 |
1 | // 3. 在字体栈里,让“替身”字体紧跟在真正的 Open Sans 字体之后 |
这个思路很简单:先让浏览器用这个调整好尺寸的 Arial 字体把字体显示出来,因为是本地字体,所以速度会很快、文字的位置会迅速固定。当真正的 Open Sans 字体下载好之后,浏览器就会立刻用它替换掉临时的 Arial「替身」。由于位置和尺寸早就被 Arial 字体固定好,所以整个替换过程在视觉上是无缝的,页面完全不会跳动。
再就是字体格式,相较于 TFF 或 OTF 等传统格式,用 WOFF2 更好。WOFF2 的压缩率极高,兼容性也特别好,尽量开发网页时都采取这个字体格式。不过有些字体不让转换成这个格式,需要特别注意一下。
你也可以看出来,我用了 unicode-range
控制了字体的字符范围、只让页面加载它实际需要的字符。比如说 Open Sans 只加载基本拉丁字符、标点符号和货币符号,Noto Sans 则只包含中文汉字字符范围(unicode-range: U+4E00-9FFF, U+3400-4DBF, U+20000-2A6DF;
)。
不同字体的视觉对齐
作为一个中文技术博客,文章中难免会出现英文单词以及代码片段。为了达到最佳的阅读体验,我会为中文字符、西文(拉丁)字符以及代码用的字符分别指定一个字体。然而这里会面临一个问题:不同的字体,即时 font-size
是一致的,但它们在视觉上的大小、重心和基线位置往往是不一样的。当这些中英字符同时出现在一行时,就会显得大小不一、高低错落,破坏了排版的和谐感。
此处令我想到高中时、一位我很喜欢的老师。当时她还不是正式教师,考核时给我们上的课讲的就是排版和字体。当时并没有认真听讲。
CSS 提供了一些属性,恰好可以让我们解决这个问题:
1 | @font-face { |
我通过 size-adjust: 94%
将 JetBrains Mono 的整体视觉大小缩小了一点,然后用 ascent-override
等属性微调了它的垂直对齐基线,最终让它和我的正文字体放在一起时,看起来没那么突兀了。
流式排版
每个人阅读博客的设备都各不相同,有用电脑的,有用平板的,有用手机的,有用小天才手表的(有吗?)。不同设备的屏幕尺寸不同,我们通常需要在多个端点处使用媒体查询来手动调整 font-size
。例如:
1 | @media (min-width: 768px) { body: font-size: 17px; } } |
这很繁琐,要知道现在世界上有多少种屏幕尺寸,一个个适配过去会累死掉。更优雅的解决方案是采用流式排版,即让字体大小像液体一样,随着屏幕宽度的变化而平滑、无缝地缩放,确保在任意设备宽度下都有最佳的视觉表现。实现这种效果,要用到 clamp()
方法。
1 | :root { |
clamp()
的三个参数分别是:
- 最小值
- 首选值
- 最大值
告别 jQuery 和 Font Awesome
优化完字体系统后,可以想想图标字体该怎么办。我的原先方案是用 Font Awesome,实际上也不是一个很好的选择。Font Awesome 是用传统的网络请求加载的,也会导致不必要的性能和阻塞渲染问题。最好的方案是使用 SVG。很多时候我们的网站只会用到一些图标字体,为此下载一整个完整字体库很没必要,SVG 的可访问性也更好。
我同时又检查了一遍博客的代码,发现主题的所有功能都被原生 JavaScript 实现。因此我移除了 jQuery 依赖。其实我都不是很明白这个主题哪里用到了 jQuery,可能是主题作者先前留下的。
提升交互体验
无障碍增强
我几乎是不会考虑「无障碍」的,过去的时候。在阅读了一些博客网站的设计想法时我意识到,实际上用着「不寻常设备」的读者可能比想象中还要多,总是要确保所有的用户都能良好地使用博客功能。当然,不只是博客,未来开发的网站也要想到这一点才行。这次重构中,我添加了一个跳过导航的按钮,它平日会被藏在屏幕视图的上方,需要使用 Tab 才可以将其唤出。Tab 也可以用来快速导航到下一个标题、链接、代码块等。
我也为正文链接添加了下划线,有用到 text-decoration-skip-ink: auto
这个属性,可以自动跳过字形,例如拉丁字符 g
、j
等。