问题表现
就在我正准备录制下个系列视频的时候,发现何方的个人小站-Markdown 工具页面下面出现了大面积的空白(如下图 1)。
这是什么情况?我第一反应可能是我忘了给代码或预览的窗口添加 overflow: auto
导致元素的整个长度直接推在了元素流里面。
![下面出现大面积空白](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/网页下方大面积空白-light.png)
![下面出现大面积空白](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/网页下方大面积空白-dark.png)
原因分析
但当我看了代码和界面以后发现是对的(如下图 2),并没有忘记添加 overflow: auto
。而且我查看 body
元素的时候发现高度是正常的,并没有包含下面空白区域的高度。这时候我感觉可能是 Edge 浏览器的 Bug。于是我试了 Chrome、Firefox、Safari 以及 Linux 和 Windows 中的各种浏览器,都能复现这个问题。确定了不是浏览器的 Bug。
![overflow: auto](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/编辑器和预览-light.png)
![overflow: auto](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/编辑器和预览-dark.png)
于是我又查看了 html
元素的高度,发现在 html
高度竟然是包含了空白区域高度的(如下图 3)。到这个时候我就确定一定是有什么元素浮动到了元素流里面,而且这个元素一定是不可见或非常小的,这就只能逐个排查可能的元素。
![html 高度](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/html高度.png)
![html 高度](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/html高度.png)
在我排查过程中发现如果把预览关掉或不预览 HTML 渲染结果(见下图 4),只预览 HTML 代码的情况下是没有空白问题的。这就可以确定是 Markdown 的渲染结果出现了问题。但渲染结果是 Markdown 解析器生成的,这又增大了排查的难度。
![关闭预览](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/关闭预览.png)
![关闭预览](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/关闭预览.png)
这个时候我突然想起来,浏览器的开发都工具是可以查看页面 3D 结构的。在复合图层里面并没有看出什么问题(见下图 5)。但当我查看 3D DOM 结构(见下图 6)并把视频拉到最下面是发现了问题——在最下面出现了几条东西。点击 3D 视图可以跳转到对应的 dom 结果里面,原来导致页面空白的罪魁祸首是公式(见下图 7)。
![3D视图复合图层](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/3D视图-复合图层.png)
![3D视图复合图层](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/3D视图-复合图层.png)
![DOM结构](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/3D视图-DOM结构.png)
![DOM结构](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/3D视图-DOM结构.png)
问题原因
我在 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;
}
![公式DOM结构](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/公式DOM结构.png)
![公式DOM结构](https://iamhefang-1310356775.cos.ap-chengdu.myqcloud.com/images/blog/code/一个absolute引用的问题/公式DOM结构.png)
问题就出在了 position: absolute
上面,因为我们的预览容器是 overflow: auto
的。在可滚动的容器里面如果存在绝对定位的元素,这个元素就会脱离容器出现在主元素流里面。也就是说如果容器没有溢出滚动的时候这个元素该出现在哪儿,在有溢出滚动的时候它还在那儿。这就造成了它前面出现的空白。
解决方案
知道了问题原因也就好解决了,三种改动较小的方案1:
- 把 katex 生成
htmlAndMathml
改为html
。 - 把类
.katex-mathml
的position: absolute
改成position: fixed
。 - 把
.katex-mathml
的父类的position
改成非static
。