自用 Next.js 博客程序之随便扯扯
简单写篇介绍文,给期末作业做准备。
因为面向路人的关系,不扯什么简单的 CSS 设计和类似 PJAX 之类的了。
基本信息
项目已开源至 Github:Cesirdy/next-blog
首先使用了如下项目:
- Next.js
- Tailwind CSS
- React
设计理念之没有设计就是最好的设计,毕竟本质是写文章的地方,不搞什么二次元花里胡哨的影响阅读的设计,同时尽量实现较高的性能。
PageSpeed Insights 性能报告说 100 分,但是整体资源大小比较大,只能说遗憾。
不讲样式和 UI 设计这种基础,目前实现了如下功能:
- Markdown 文章解析
- 简单的文章排版优化(基于 @sofish 的开源项目 typo.css)
- 文章内目录跳转(自动检测文章内所有标题并生成)
- 文章内图片懒加载并自动优化格式 & 同站链接预加载(兼容自 Next.js 自带组件)
- 评论组件(Disqus X DisqusJS 并懒加载)
- 代码高亮
- 分类 & 归档功能(带有分类过滤)
- 深色模式(带缓存记录)
- 独立页(与文章页实现方式一样)
- 链接页
- 导航栏
- 移动端自适应
- Sitemap(借助插件)和 RSS(脚本生成)
文章生成
类似 Hexo 等静态站点生成器的思路,本地写文章(文件形式)并通过程序生成为一个完整的站点。
流程大致是:
- 写文章
- 处理文章信息
- 生成为 JSON + HTML
- 部署
大概就是这样吧:
+---------+ +--------+ +--------+ Build +-------+
| Sources | -----> | Github | --------> | Vercel | --------> | Pages |
+---------+ Push +--------+ trigger +--------+ Deploy +-------+
一般主流都是只生成 HTML,但是 Next.js 可以同时生成包含文章信息的 JSON。
直接通过链接访问页面时会加载 HTML,在这之后通过页面内点击访问其他页面,会加载 JSON,通过 JSON 的内容来动态修改页面,从而减少用户加载开销。
也就是不用每次访问其他页面都加载一整个 HTML 以及其包含的需要加载的 JS 和 CSS。
生成的 HTML 中,首页展示最新 5 篇。
归档页展示所有文章,可以根据文章分类选择性展示特定分类的文章。
文章采用 Markdown 格式并通过 next-mdx-remote
这个库解析展示,只能说好用。
排版修改自 @sofish 的开源项目 typo.css,主要修改了一些符合个人喜好的东西。
像代码高亮及目录也是提升阅读体验的一环。
next-mdx-remote
默认会将图片和超链接直接解析为 HTML,但是可以通过 components
将其解析为 Next.js 自带的图片和链接优化组件。这部分还是挺简单的。
样式
样式部分没有采用传统的 CSS 实现方式,而是使用了 Tailwind CSS。
一般来说,一个网站越复杂,样式也就越多,CSS 文件也越大,维护难度也会提升。
而近年以 Tailwind CSS 为代表的 Atomic CSS 也逐渐火了起来。
简单来说,Atomic CSS 是一种 CSS 编程思路,它倾向于创建小巧且单一用途的 class
,并多次复用。
简单的例子:
<style>
.text-white { color: white; }
.bg-black { background-color: black; }
.text-center { text-align: center; }
</style>
<div class="text-white bg-black text-center">hello Atomic CSS</div>
看到以上的示例,可能很快就想到,直接使用行内样式不是更好吗,还省去了 Atomic 类的定义。这个问题可以从样式编写、一致性、功能和缓存四个方面来回答。
在样式编写方面,Atomic CSS 可以充分利用 CSS 预处理器和后处理器进行样式编写,而行内样式缺乏成熟的工具支持和维护。
在一致性方面,Atomic CSS 框架通过预定义的设计系统实现一致性,而行内样式和传统 CSS 类定义的可选值没有限制。
在功能方面,Atomic CSS 支持媒体查询和状态处理,而行内样式缺少这些功能。
在打包方面,Atomic CSS 样式定义和 JS 逻辑分离,修改元素的 class
属性通常不会影响最终打包输出的样式文件,而行内样式的修改会导致整个 bundle
的改变。
与此同时,很容易也能想到:样式越多,复用的几率也就越大。因此使用 Atomic CSS 通常可以得到一个相比之下较小的 CSS 文件。
使用 Atomic CSS 相较于传统 CSS 方法,CSS 产物大小与项目复杂程度和组件数量之间的关系不再是线性正相关。随着组件数量的增加以及可复用的 CSS 规则增多,最终的 CSS 产物大小与项目复杂程度呈对数关系。
目前博客的 CSS 经过压缩传输后仅有 2.5 kB,而之前使用传统 CSS 编写的旧博客则高达 6.2 kB,实际不经过压缩的原尺寸更大。
深色模式
至于深色模式,则是为了美观牺牲了一定功能性。
目前采用的方案是:
- 首次加载,检测用户系统设置偏好,即是否为深色模式
- 将用户偏好计入浏览器缓存,并通过 CSS 的
@media
设置样式,同时修改 HTML 类名。 - 用户点击切换按钮后,通过修改类名以实现应用不同样式。
- 二次访问,查询浏览器缓存并应用样式,以此实现记忆用户偏好功能。
同时也会查询缓存并在按钮上应用样式以提示用户目前的模式,比如有个蓝色下边框。嗯。
评论
国内在多年前,大概是 2016 年左右,是有“多说”这家第三方评论系统的,但是倒闭了。
后面只能说没有“多说”这么好用的了。
秉承着白嫖还要稳定的原则,没有选择各个自建评论系统的方案,选择了 DisqusJS 的方案。
DisqusJS 的反代目前是使用了 Vercel,但是国内的访问速度也还是欠佳。只能说勉强能用。
然后做了个简单的懒加载,点击按钮才会加载对应组件,毕竟 Disqus 还是挺臃肿的。
杂项
一些杂的简单提一嘴,不展开了。
返回顶部使用了最简单的锚点,毕竟能用越少的 JS 越好。至于这个平滑的返回顶部可以阅读往期文章:《关于页面滚动的两个 CSS 属性》
链接页尝试性地使用了 grid
布局,相当不错。
文章信息的处理比较弱智,目前不知道对性能有没有影响。
像 RSS 和 Sitemap 这两个,只有 RSS 的通过文件生成感觉还算比较优雅。