就在我正准备录制下个系列视频的时候,发现何方的个人小站-Markdown 工具页面下面出现了大面积的空白(如下图 1)。 这是什么情况?我第一反应可能是我忘了给代码或预览的窗口添加 overflow: auto 导致元素的整个长度直接推在了元素流里面。
图1 - 下面出现大面积空白
原因分析但当我看了代码和界面以后发现是对的(如下图 2),并没有忘记添加 overflow: auto。而且我查看 body 元素的时候发现高度是正常的,并没有包含下面空白区域的高度。这时候我感觉可能是 Edge 浏览器的 Bug。于是我试了 Chrome、Firefox、Safari 以及 Linux 和 Windows 中的各种浏览器,都能复现这个问题。确定了不是浏览器的 Bug。
图2 - overflow: auto
于是我又查看了 HTML 元素的高度,发现在 html 高度竟然是包含了空白区域高度的(如下图 3)。到这个时候我就确定一定是有什么元素浮动到了元素流里面,而且这个元素一定是不可见或非常小的,这就只能逐个排查可能的元素。
图3 - html 高度
在我排查过程中发现如果把预览关掉或不预览 HTML 渲染结果(见下图 4),只预览 HTML 代码的情况下是没有空白问题的。这就可以确定是 Markdown 的渲染结果出现了问题。但渲染结果是 Markdown 解析器生成的,这又增大了排查的难度。
图4 - 关闭预览
这个时候我突然想起来,浏览器的开发都工具是可以查看页面 3D 结构的。在复合图层里面并没有看出什么问题(见下图 5)。但当我查看 3D DOM 结构(见下图 6)并把视频拉到最下面是发现了问题——在最下面出现了几条东西。点击 3D 视图可以跳转到对应的 dom 结果里面,原来导致页面空白的罪魁祸首是公式(见下图 7)。
图5 - 3D视图复合图层
图6 - DOM结构
问题原因我在 Markdown 生成 HTML 的时候使用的是 katex 来渲染公式,默认情况下它会生成两套 DOM 结构,一套 mathml 用于读屏软件或搜索引擎等识别这是公式、另一套是 html 它用于渲染显示我们看到的公式。
为了不让 mathml 和 html 同时显示出现,katex 把 mathml 设置成了 position: absolute 且只有一个像素大小。
.katex-mathml { clip: rect(1px, 1px, 1px, 1px); border: 0; height: 1px; overflow: hidden; padding: 0; position: absolute; width: 1px;}
图7 - 公式DOM结构
问题就出在了 position: absolute 上面,因为我们的预览容器是 overflow: auto 的。在可滚动的容器里面如果存在绝对定位的元素,这个元素就会脱离容器出现在主元素流里面。也就是说如果容器没有溢出滚动的时候这个元素该出现在哪儿,在有溢出滚动的时候它还在那儿。这就造成了它前面出现的空白。
解决方案知道了问题原因也就好解决了,三种改动较小的方案1:
- 把 katex 生成 htmlAndMathml 改为 html。
- 把类 .katex-mathml 的 position: absolute 改成 position: fixed。
- 把 .katex-mathml 的父类的 position 改成非 static。