为什么塞一张 <img> 到 <div> 下并设置 100% 高度会导致 <div> 溢出?

陪她去流浪 桃子 阅读次数:85

标题描述得已经很清楚了,直接上例子。如果尝试在图片中滚动,发现是可以的:

源代码如下:

1
2
3
<div style="height:100px;overflow:auto;">
  <img src="/favicon.ico" style="height:100%;">
</div>

别问我为什么要在这里刻意添加个 overflow:auto;,那是因为我发现我上上上……层的仅有一个子元素<ol>列表竟然因为这张图片而滚动起来了,6️⃣!只是为了缩小复现范围。

如果用 JavaScript 查询 div.scrollHeight,会发现确实比本身的高度要高几个像素,大概是 106px 左右。

所以这莫名其妙多出的 6 个像素是哪里来的?[doge][doge][doge] 没有 border,完全 100% 高度。


根因:<img> 也属于是 inline(内联/行内)类型元素,渲染引擎在排版的时候会像普通文字一样按照基线(baseline)对齐 基线下面还有 descender,那就是导致溢出的原因。

看下来的来自维基百科的图比较好理解,图中高亮的那条线就是基线(baseline):

图片来源:Baseline (typography) - Wikipedia

知道根因了那就好办了:

  1. 让它变成块级元素,不参与 inline 排版:

    1
    2
    3
    
    img {
      display: block;
    }
    
  2. 不要基于基线对齐:

    1
    2
    3
    
    img {
      vertical-align: middle;  /* 或 top, bottom 也行 */
    }
    
  3. 彻底干掉字体:

    1
    2
    3
    
    div {
      font-size: 0;
    }
    

以前没少被折腾。顺着《Baseline (typography) - Glossary | MDN》这篇文章看下去,收获会不少。