右缘的一列刻度

1138 字 · 3 分钟#设计#交互

给自己攒了一个「思考流」页面:几十条零散的短想法,按时间倒序排成一条流水。做完内容才发现真正难的是导航——这一页没有标题,条目短则一句话长则一段,传统的那套页面导航全部失效。这篇记录我最后落下的方案:右缘的一列刻度。

先玩再读:

2024

一条占位的思考。预览卡里摘的就是这段文字的开头,正文写什么,卡片就预览什么,不用单独维护摘要。

刻度的长短是有语义的:长刻度是年份,短刻度是条目。不用一个字,层级就说清了。

把指针沿着刻度列慢慢滑,注意旁边刻度的长度变化——这就是正文里说的鱼眼。

2023

试着点击任意一根刻度,滚动区会平滑跳到对应的条目。

滚动这个区域时,右边有一根刻度始终比别的黑——它标记的是你正在读的位置。

判定带在容器上部三成处。一条思考的顶边越过这条线,就算「正在读」。

2022

从刻度斜着把指针移向预览卡,卡片不会消失——刻度列外围有一圈看不见的容错区。

最后一条。滚到这里,右边最下面那根刻度应该正好变黑。

滚一滚左边,摸一摸右边的刻度

为什么现成的方案都不行

文字目录是第一个排除的。目录吃标题,而思考流的条目根本没有标题——总不能把每条的前十个字排成一列,那是另一种噪音。

Minimap(VS Code 那种缩略图)太重了。它把整页内容按比例缩小挂在旁边,对代码有用,对一页中文短句毫无信息量,还抢视线。

裸滚动条不表意。它只回答「你在页面的几分之几处」,不回答「这附近有什么」「那条想法在哪」。

我要的东西介于三者之间:能表达结构(哪年、多少条)、能预览内容(不用跳过去就知道是哪条)、还几乎不可见(内容才是主角)。最后落在「刻度」这个形态上——地图比例尺的语言:一根短线代表一个条目,一根长线代表一个年份,层级不着一字。

存在感的定价

静止状态下,刻度是 22% 透明度的细墨线,视网膜的余光知道「右边有个东西」,但读正文时它完全消失。我给导航的定价原则是:存在感和使用频率成正比付费。读者 95% 的时间在读,导航就该按 5% 的存在感收费。

同理,两条硬性的「不渲染」规则:条目少于 3 条时整个组件不出现(3 条内容用不着导航);窄于 xl 的屏幕上也不出现——这套交互的核心是 hover,触屏没有 hover,硬移植过去只会变成一列误触点。设计不成立的环境里,正确做法是整个不给,不是给个残废版。

鱼眼:手感是长度差给的

指针滑到刻度列上,被指的那根伸长 10px,邻近的伸 5px,再远伸 2px——一个离散版的 macOS Dock 鱼眼。这不是装饰,是功能:刻度只有 2px 的命中高度,纯靠光标悬停很难知道自己停在哪一根上,长度的波峰就是光标位置的回显。手感的本质是反馈的分辨率。

预览卡:指哪看哪

hover 时弹出的预览卡有个关键决定:它钉在被指的那根刻度旁边,跟着手指走,而不是固定在某个角落。眼睛不用在「手指的位置」和「信息的位置」之间来回跳,指哪看哪。

卡片里的预览文本没有单独的数据源——组件挂载后直接从渲染好的正文 DOM 里摘前 110 个字:

const el = document.getElementById(item.id)
const text = el.querySelector('.prose')?.textContent
previews[item.id] = text.replace(/\s+/g, ' ').trim().slice(0, 110)

写思考的时候永远不需要维护「摘要」这个字段,正文即预览,单一事实源。

两个看不见的细节

容错区。 有个经典的 hover 走廊问题:光标从刻度斜着奔向预览卡,中途会离开刻度的命中区,卡片闪一下就没了。常见解法是 JS 延时关闭,但更干净的解法是几何的——给整个刻度列的容器加一圈看不见的 padding(左侧 4rem、上下 1.5rem),mouseleave 挂在容器上。光标在这条隐形走廊里随便走,hover 不丢。

阅读位置。 哪根刻度该标黑(表示「你正在读这条」)?拿 scrollTop 算阈值很脆,我用 IntersectionObserver 划了一条判定带:

new IntersectionObserver(callback, {
  rootMargin: '0px 0px -70% 0px',
})

底边收缩 70%,等于宣布「视口上部 30% 是阅读区」。条目进入这个带就是候选,取文档顺序最靠前的那个。上面 demo 里滚动时变黑的那根刻度,就是这条带在工作。

顺手的收尾

点击刻度平滑滚到对应条目,hash 用 history.replaceState 写进地址栏而不是 push——逛完二十条思考按返回键,应该直接回到上一页,而不是把二十次跳转逐个退回去。

中间的内容列倒没什么花样:按年分组,一条纵向墨线串起当年的条目,每条一个骑在线上的小圆点(圆点填纸色,在墨线上镂出一个缺口)。线是时间,点是想法,右缘的刻度是这条线的全局缩影。三层是同一个隐喻。