之前总喜欢用 ol>li 格式来记录内容,虽然自我感觉有序列表会让内容更清晰,但从页面显示角度看体验不太好。一个重要的因素就是 ::marker 即列表项的 1,2,3 和上文的普通段落没对齐。

首先,我们要知道一个属性,list-style-position. 虽然设置为 inside 可以立刻满足我们的需求,但是这会让 li 换行后的内容没有缩进,这直接破坏了 li 的基础样式要求,直接 pass 掉。

然后就是我们尝试的重点:调 olmargin-left 了。

一开始就是对着浏览器,肉眼调。之前没发现啥问题,直到自己在 Win、Ubuntu、Mac 等各端上看到实际效果,明确这样调无法满足跨端效果。

发现各端效果不一的原因,是因为字体渲染的差异(准确说是各个系统拥有的字体不同,实际渲染的字体就不同)。所以,我们有了 2 个解决思路:

  1. 区分端,不同端设置不同的 margin
  2. 直接统一字体(使用 webfont)

最后的事实证明,思路 2 才是整个网页渲染一致的最优解,可惜自己一开始还是执着于减少对外部资源的引入。

来看看对 思路1,走了哪些弯路:

  1. 尝试用 JS 判断操作系统类型。结果发现基本可用的方法,都被标注为了不稳定或即将废弃的。难道这么“基础”的功能都没有?后来我发现这是“网页标准”的指导思想:不建议通过判断 OS/浏览器 的方式来写特有的内容,而应该通过 feature-test 来写针对性处理。大概是因为前者不可枚举且不一定符合预期(系统+版本+配置差异),后者才是真真切切的。

  2. 沿着这个思想,咱们就不检测 OS 了。不过,人的思想很难完全转弯啊——放弃 OS 检测后,当时的想法还是对着“各端字体不同”这个想法在走,于是决定检测“渲染时实际使用的字体”,然而再基于字体去设置 margin。 可惜啊,这个也不靠谱。搜索并尝试了基于 canvas 的方案,发现不行——要能检测这个,必须有个前提——你得有一个全端都可以渲染的字体,这样才能通过设置 font-family 来枚举实际使用的字体。但是——我都有全端可渲染字体了,我还整这干啥呢?嗯,其实理论上来说,像 sans-serif, monospacce 等字体,各端都可以渲染,所以也算是全端字体了。然而这种字体其实是一个名字——也就是各个端把自己有的一些字体叫这个名,但实际渲染的字体不同。总之,字体检测不完美。

  3. 我终于想到应该直接测试相应 marker 的宽度了。可惜一时脑抽,想到的是创建一个与 marker 内容一样的元素,然后再测试这个元素的宽度,进而确认 marker 的宽度。看起来也应该没问题啊? 但是,实际测试还是不对…… 或许是这个元素的一些其他属性,与 ::marker 不同吧。

  4. 终于,脑子开窍了——我直接看各端实际渲染的 ::marker 宽度不就行了???(可能是一开始患上了 XX不能检测PTSD 吧,竟然最直接的方法最后才想到)。解决了一个基础问题——::marker 元素(或者所有的伪类)不能通过 querySelector 拿到,而是要用 getComputedStyle 来拿。搞定这个,预期效果终于达成了……

最后再来看为何我认为 思路2 是最优解。从后面的经验来看,主要有 2 点:

  1. 样式对齐简单:使用一套 webfont,在各(现代)浏览器、各操作系统下,目前看渲染结果都是一致的。故样式设置时省心,没必要搞太多特殊处理。
  2. 成本并不高: 样式对齐我目前只涉及数字、英文、部分符号(如引号),其实产出的 webfont 字库是很小的(10K级别),不必太担心网络开销。

实际上,因为我用 getComputedStyle 已经处理好了 ::marker 的对齐问题,所以这里我是没有用 webfont 的;但在后面处理 blockquote 的引号样式时,我怕了——要把引号固定到特定位置,并不是简单获取它的宽度就行的。这要是按之前的思路,应该得逐个端去对着浏览器调了。想想算了,直接上了 webfont. 体验下来,不错,省心省力。