跳转到内容

空白节点

刀刀

1/3/2025

0 字

0 分钟

场景重现

在介绍空白节点之前,首先看一个案例。代码如下:

html
<style>
  * {
    margin: 0;
    padding: 0;
  }
  
  div {
    background-color: red;
  }
</style>

<body>
  <div>
    <span></span>
  </div>
</body>

此时打开页面是没有背景色的,因为没有内容把他撑开。如果给 span 添加内容,则会因为有内容高度把它撑开,显示红色的背景色。

现在给 span 修改为行内块元素,代码如下:

css
span {
  display: inline-block;
}

此时页面显示了红色空白,效果如下:

pP58f5d.png

就像一个空白的幽灵节点一样,把父盒子撑开。

前置知识

首先我们需要了解一个概念,叫做基线,在所有内联相关模型中,凡是涉及到垂直方向的排版或者对齐的,都离不开最最基本的基线(base-line),那么基线是怎么定义的呢?在维基百科中有这么一个示意图:

tupian

根据图片中标示,字母 x 的下边缘(线)就是基线。

在 CSS 中有两个重要属性,line-heightvertical-align 都与基线有关,line-height 行高的定义就是两个基线之间的距离,vertical-align 的默认值就 baseline,也就是基线对齐。对于内联元素,我们要认识到,虽然 vertical-alignline-height 看不见,但实际上到处都是

那么标签元素的基线如何确认呢?在 CSS2 的可视化格式模型文档中有这样一段话:

The baseline of an ‘inline-block’ is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its ‘overflow’ property has a computed value other than ‘visible’, in which case the baseline is the bottom margin edge.”

也就是说:一个 inline-block 元素,如果里面没有 inline 内联元素,或者 overflow 不是 visible,则该元素的基线就是其 margin 底边缘,否则,其基线就是元素里面最后一行内联元素的基线。

因此,当 <span> 中空白并且为 inline box 的时候,div中似乎依然有一个和类似 x 字符的空白节点,来撑起 line box 的高度。为了帮助我们理解,在这里我们可以把字符 x 看作为“幽灵空白节点”具像,它不占任何宽度,看不见也无法通过任何方式获取,但又似乎真实存在,它的大小会受 font-size 的影响。

认识“幽灵空白节点”

在 HTML5 规范中有这样一句话:

"Each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a 'strut'."

每个行框盒子都以一个具有元素的字体和行高属性的零宽度行内框开始。我们称这个假想的盒子为"支柱"。

HTML5 文档声明中,内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样,但又确确实实地存在,表现如同文本节点一样,因此,在张鑫旭大佬的《CSS 世界》一书中根据特点,将其称之为“幽灵空白节点”,也就是官方规范中的 “strut”。

消除“幽灵空白节点”的影响

终于找到并认识了“幽灵空白节点”,那么对于这种无法获取却又真实影响我们样式的“节点”,我们应该如何消除它带来的影响?

  • 1、让vertical-align失效:vertical-align属性对于块级元素是无感的,因此我们只需要为元素设置dispalyblock即可;
  • 2、修改vertical-align属性值:修改其默认值baseline值为其他属性值,使其不再相对基线对齐;
  • 3、修改line-height的值:上面我们说过line-height的定义是两基线之间的距离,因此在上面例子中,图片下面的空隙,实际上是“幽灵空白节点”计算后的行高值和基线的距离,因此,只要line-height足够小,便可以消除图片下面的空隙。(注意这里是要在div上设置line-heght,然后让divinline boxes继承line-height属性