***
上一版的文章页,我自己读自己的文章,读到第三段就开始烦。
毛病能一条条指出来:
- 桌面端,正文挤在屏幕右边一条 480px 的窄条里。一行没看几个字就到头,长文读起来像排队。
- 手机端更怪:一打开先看到大半屏封面图,正文要往下翻才轮到。
- 背景图填满高度、裁掉两边。图一宽,左右就缺一块,永远看不到完整的那张。
- 再往下滚,上下篇、评论区、附件墙挨个冒出来,各占一块,规规矩矩。
每一项单看都没坏。凑在一页里,就是一篇文章让人不想读完的样子。
这篇讲的是把它们全部拆掉、重做的过程。

我用了整整一晚,把这块地方推倒重来
先摆时间。我把那个沙盒目录(_proto-detail/)里每个文件的修改时间翻出来,排了一遍:
9 月 25 日 23
动手,建目录
00 第一版正文排版
01 嫌手动截图太慢,写了个截图工具
03 还在调正文的逐块入场
04 一口气把外围六件做完:上下篇、画廊、灯箱、文契、评论中间空着五个多小时,我睡了
10
起来接着干,正文定稿
10 文章头
11 标题两翼
12 章节轨、进度柱
12 背景留白的硬切线修复
12 原型收尾
13 v0.4.6 落地
14 v0.4.7 落地

13
和 14 是两个版本落地的时刻,站点是自动部署的,推上去就在线上。从起念头到全部上线,不到十五个小时。
大半时间没花在写代码上,花在试上:把东西摆出来、截图、盯着看、不行就删。所以我先开了一个沙盒目录,不参与构建、对 git 隐形,里面随便乱来,废掉的实验品不用擦屁股。
原型最后留下 12 个样式、9 个行为脚本、11 张设计令牌表(配色、字号、节奏全在里面调),后来一行不改搬进了站点。
先把成果摆出来,账留在后面算。
现在长这样

① 首屏:一张完整的图,一块安静的牌子

背景图现在完整显示,一条边都不裁。图放不满的地方,用这张图自己的模糊放大版垫满:远处是一片色雾,近处和图片边缘的颜色接得上,看不到接缝。
正文上方那块黑底牌子是文章头,压着背景图,宽度和正文对齐。
② 读到哪里,一眼就知道

屏幕最左边那根细柱子是进度,口径只算正文,右上角那个百分比跟着它走。
柱子旁边一排刻度是章节轨,每一根对应一个标题,位置按标题在正文里的真实位置排——刻度疏的地方,就是文章里没写多少的地方。鼠标往左边一靠,它展开成一张目录,点哪去哪。
正文里的标题两侧还有箭头,管「下一节」这种小步移动,跨章节的活交给轨道。左下角两枚圆钮:上面是导航开关,下面那只是眼睛。
③ 文章里的图,排成一面墙

正文里的图和图令里放过的图都会被收集起来,在文末排成一面摄影墙。点开其中任意一张,是整组翻页的灯箱,方向键和 ESC 都能用,底下有计数。
④ 需要导航的时候,它从顶上滑下来

上一版文章页顶上是常驻的导航栏。新版把它请下去了,页面里只剩文章。要导航,按左下角那个开关:导航条从屏幕顶上滑下来盖住背景,再按一次、点空白、或者按 ESC,收回去。它不占一点版面高度。
文章读完,文末还有上下篇(左粉右青两张卡,缺哪一篇就画一张虚线占位卡)、评论区,和一张归色文契——作者、日期、许可协议,还有一行「距今已经过去」,每秒都在跳。它们和正文一样,滚到哪,浮到哪。

背景为什么会自己换
文章里会出现 ::img{} 这种记号,这是本站特有的图令。那行字在地面上不显示图片,它是个信号:滚到这里,背景该换图了。
信号滚过屏幕上往下 40% 的那条判定线,背景就淡出换成新图,380 毫秒走完。做成「越线才触发」,是因为滚动速度不均匀,跟手算距离的话,快速滚动时会直接硬切。
往回滚,要退过 48px 才换回去。不然信号停在判定线附近来回蹭,背景就会闪。
手机上没有背景层(小屏幕上图会和字打架),图令就在原位置直接显示成一张普通图片。一个写法,两种用途。
藏起来的几个决定
导航栏整条拿掉。 新版文章页里没有导航栏,也没有页脚,整页只剩文章。代价很明确:读者失去了站内导航。这笔账是第二天还的——v0.4.7 做了一个从顶上滑落的导航层,需要的时候请它下来。我觉得这样比一直摆在那里好。
顶栏做成「滑下来盖住」,不压一行。 一开始想在页面顶上留一条固定栏,后来算了:阅读页最贵的是竖向空间,给导航切走一条,正文就少一条。滑下来盖在背景上,不占高度。
进度柱搬了三次家。 第一版贴屏幕最右边,看着太远;搬到阅读栏的右边界,又夹在正文和空白之间,别扭;最后定在屏幕最左。高度也折腾过:先跟着文档走,太长;缩到 58vh,太短;最后是「跟屏幕一样高,但裁到正文区间」——正文铺满整屏它就贯穿整屏,正文只剩半屏它就露半屏,读完就消失。
一个做了很久、最后整套撤掉的效果。 我本来想做「章节取景窗」:滚到一章时,在压暗的底幕上开一扇没被压暗的窗,让标题在窗里浮现。做到尽头卡在可读性上——正文是浅色字,压在没被压暗的亮图上会糊成一片。要救它就得给文字加暗底,那就不叫「开窗」了。最后整套删掉,只留下「正文逐块入场」这一件事。拿可读性换好看的事,不干。
两条硬切线,跟了我一晚上
第一条:留白和图片之间,有条线。
背景图完整显示之后,四周会留白。我把这张图的模糊放大版垫在下面去填,颜色接不上就调亮度、调饱和度,调了好几轮,边上还是一条清清楚楚的线。
后来不调了,去量。沿着图片边缘逐像素扫「相邻两行的平均差」:全图的中位数是 1.0,图片内部正常的起伏最大 8.4,而那条边界是 37.3。量出来的是硬边。
根因很气人:垫底的模糊版按「裁切放大」取景,主图按「完整居中」取景。同一个屏幕坐标,两层取到的是原图里完全不同的像素,颜色当然对不上。证据是上下两条边的亮度差方向相反,一个 +39.5,一个 −14.7。
修法要三件事凑齐,缺一不可:晕层与主图同框对齐、放大补偿模糊带来的边缘透明、主图边缘 56px 羽化,把最后 1px 的落差摊平。修完再量,37.3 跌出榜单,比图片内部的正常起伏还低。
顺手还有个更隐蔽的:
mask-composite: intersect旁边不能写-webkit-mask-composite。两个名字指向同一个属性,后者会把前者盖掉,而它在标准里是无效值,整条声明回落成「并集」。看着写了羽化,其实一点都没生效。
第二条:切换背景的那一下,卡半秒。
背景图换回来的时候要重新光栅化,成本大约等于「模糊半径 × 面积」。毯层 120px、晕层 56px 的时候,切换会掉一个 216 毫秒的长帧,手能感觉到卡。把半径降到 56 / 16,最长帧掉到 66 毫秒,长帧归零,肉眼已经看不出区别。
还试过几个「优化」,方向是反的:给图层加 will-change: transform,平均帧从 16.7ms 涨到 102.7ms;让所有图层保持可见、想保住栅格,更糟。有些直觉在浏览器里不成立。

还没验完的部分
诚实交代,这套东西目前只保证「我天天在用的场景」是好的:
- 移动端的导航层形态(汉堡菜单、右滑抽屉在窄屏上好不好用)
- 灯箱和导航层同时出现时的前后关系
- 挂在墙上的 niko 会不会正确停在正文两侧的挂壁线上
- 低配设备上切换背景的手感
这些都排进 v0.4.8 了。
后记
写这篇时我回去翻那些文件的修改时间:23
、00、01、03、04……一串时间戳排在那里,像一行脚印。
那天夜里改得最多的东西,你现在看不到,它们都被删掉了。留下来的部分有个共同点:经得住盯着看。
现在我自己读自己的文章,能读到结尾。
感谢你的聆听。
