在宽屏显示器上如果将文章正文撑满整个视口,视线从行尾跳回下一行行首时容易串行;而在手机端,过长的代码块或宽表格又常常把页面横向撑出滚动条。
本文从单行字符宽度(Measure)、中西文字体栈回退、CSS Grid 响应式断点,以及基于 IntersectionObserver 的目录滚动高亮四个方面,整理长文阅读页的实现细节。
中英混排的字体栈、行宽与行高
在长文排版中,影响阅读舒适度的三个基础参数是字体栈(Font Stack)、单行字符宽度(Line Measure)与行高(Line Height):
- 兼顾加载速度与屏显效果的字体栈:
- 正文无衬线字体(Sans-serif):优先调用操作系统自带的黑体(macOS 的
PingFang SC、Windows 的Microsoft YaHei UI、Linux 的Noto Sans CJK SC),无需等待网络字体下载即可渲染; - 标题衬线体(Serif):页面主标题与文章标题使用
Noto Serif SC(字重 600),与无衬线正文形成层级区分; - 代码与终端等宽字体(Monospace):统一使用
'JetBrains Mono', 'Fira Code', 'SFMono-Regular', Consolas, monospace,确保字符0与O、1与l易于分辨。
- 正文无衬线字体(Sans-serif):优先调用操作系统自带的黑体(macOS 的
- 控制单行行宽(
62ch~74ch): 中文长文较舒适的单行字数为 36 ~ 45 个汉字(约对应680px~780px的正文净宽)。当桌面视口宽度达到1240px时,不让正文无限横向拉伸,而是将右侧空间留给常驻章节目录(Sticky TOC)与卡片内边距。 - 正文行高与段落间距:
中文方块字没有英文的上下延展笔画(Ascender / Descender),如果直接沿用英文站点常见的
line-height: 1.5,中英混排并夹杂行内代码框时就会显得上下拥挤。将正文行高设为1.8~1.85、段落底边距设为1.25em,能减轻长文阅读的压迫感。
响应式双栏网格与 minmax(0, 1fr) 宽度约束
在桌面端(视口宽度 > 1024px),文章页采用「左侧主阅读卡片 + 右侧 256px 常驻章节目录」的双栏网格;在平板与手机端(<= 1024px),目录移至正文上方并支持折叠,主阅读区收敛为单列。
编写双栏 CSS Grid 时,如果直接写成 grid-template-columns: 1fr 256px,一旦文章里出现一段不换行的长命令,左侧这一列就会按内部代码块宽度向右撑开。原因在于 CSS Grid 轨道中 1fr 的默认最小尺寸是 auto(即内部不可折行子元素的 min-content 宽度)。
要限制列宽不超出视口,需要将主内容列声明为 minmax(0, 1fr),并在主卡片上显式加上 min-width: 0:
1 | /* 长文双栏响应式网格与防横向溢出样式 */ |
区分普通数据表与代码高亮表格的滚动规则
为了支持代码行号对齐,不少静态生成器的代码高亮输出结构为 <figure class="highlight"><table><tr><td class="gutter">...</td><td class="code">...</td></tr></table></figure>。
如果直接用 .article-content table 选择器给所有表格加上单元格边框和 display: block; overflow-x: auto;,代码块内部用于排版行号的双列表格也会被加上边框,导致行号与代码错位。
使用 :not(.highlight table) 可以将两类表格的样式与滚动容器分开:
1 | /* 1. 多行代码块:由外层 figure.highlight 承担深色背景与局部横向滚动 */ |
同时,为了避免点击目录跳转章节时目标标题被顶部常驻导航栏遮挡,需要为正文标题设置 scroll-margin-top:
1 | .article-content h2[id], |
目录滚动联动、代码复制与图片灯箱
在构建期生成静态目录 HTML 后,客户端可用原生 JavaScript 实现三项阅读辅助功能:
1. 章节目录滚动追踪(Scroll Spy)
使用浏览器原生的 IntersectionObserver 替代传统的 scroll 事件轮询:
1 | const tocLinks = Array.from(document.querySelectorAll('[data-toc-list] a')); |
2. 剥离行号的代码复制与矢量图灯箱
- 代码复制:点击代码块顶栏的「复制」按钮时,仅读取
td.code pre节点的纯文本内容写入navigator.clipboard,避免把左侧的1 2 3行号混入剪贴板; - 图片灯箱(Lightbox):正文中的
<figure class="article-diagram">默认按卡片宽度自适应展示;点击架构图时,可放大查看原图或在新标签页打开 SVG 文件。
长文排版与移动端适配自检表
| 测试场景 | 验证方法 | 核对结果 |
|---|---|---|
| 手机端 390px 视口防溢出 | 浏览器切换至 390×844 视口打开含长命令与宽表的文章 |
document.documentElement.scrollWidth === window.innerWidth,页面无整体横向滚动条 |
| 代码复制内容 | 点击任意多行代码块复制按钮并粘贴至终端 | 仅包含命令文本本身,不含行号数字与首尾多余空行 |
| 表格与代码样式隔离 | 同页包含 Markdown 参数对比表与代码块 | 数据表带网格边框且可左右滑动;代码块内部无多余单元格边框 |
| 目录锚点偏移定位 | 点击右侧目录任意 h2/h3 条目 |
页面滚动至对应标题,标题上方留有 88px 间距不被顶栏遮挡 |