先记住这个答案
img 是行内替换元素,它参与文字排版,和文字排在同一行里。vertical-align 的默认值是 baseline,所以图片的底边对齐的是文字基线。基线下面还要给 g、j、y 这类字母的下伸部分留空间,即使容器里一个字都没有,这段空间也在,于是图片底下就多出了几像素空白。把图片改成 display: block,或者把 vertical-align 改成 middle、top、bottom,空白就没了。
- 行内图片底边默认坐在文字基线上
- 基线下方留给字母下伸部分,所以有空白
line-height越大,行盒越高,空白可能越明显- 可改块级元素或调整垂直对齐
先看现象:一张图片和一个边框
给容器加个边框,里面只放一张图片,底部会露出一条缝。
<style>
.box { border: 1px solid red; font-size: 16px; line-height: 1.5; }
.box img { width: 100px; height: 100px; }
</style>
<div class="box">
<!-- 红框高度不是 100px,而是 100px 再多几像素 -->
<img src="avatar.png" alt="" />
</div>多出来的高度和字体、font-size、line-height 都有关,所以不同页面上缝的宽度不一样,常见是三四像素到七八像素。把 .box 的 font-size 调大,缝会跟着变宽,这说明空白来自文字排版,和图片本身无关。
基线、行盒和支柱
行内元素排版时,每一行会生成一个行盒,里面的文字、图片、inline-block 都按 vertical-align 摆放。默认的 baseline 就是让大家的基线对齐:文字的基线是字母 x 的底部,图片没有文字,它的基线就是自己的下边缘。
那容器里没有文字,基线从哪来?规范规定,每个行盒开头都有一个看不见、零宽度的「支柱」,它带着父元素的字体和 line-height。可以把它想成一个隐形的字母,它的基线决定了图片放在哪,它基线以下的部分,也就是下伸空间加上 line-height 分到下方的半行距,就成了图片下面的空白。
line-height怎么影响这条缝line-height比字体本身高时,多出来的部分会平分到文字上下,叫半行距。line-height越大,支柱基线以下占的高度越多,缝越宽。所以同一张图,在line-height: 1和line-height: 2的容器里空白不一样大。给父元素设line-height: 0能消掉空白,原理就是把支柱压扁了,不过这会影响容器里其他文字,一般不推荐。
几种修法怎么选
最常用的是给图片加 display: block。图片变成块级元素,不再参与行内排版,也就没有基线和支柱的问题。适合图片独占一行的场景,比如 Banner、商品主图。
如果图片要和文字排在同一行,比如头像旁边跟着用户名,就不能改成块,这时改 vertical-align。middle 会把图片的中点对齐到父元素基线往上半个 x 高度的位置,看起来和文字居中;top、bottom 分别对齐行盒的顶部和底部,都能消掉底部空白。
font-size: 0 也能让支柱消失,但容器里的文字要重新设字号,属于绕路的写法,只在 inline-block 横排的老布局里偶尔用到。
容易答错的地方
- 以为空白是
margin或padding - 在开发者工具里看图片的盒模型,
margin和padding都是 0。空白属于父元素的行盒,不属于图片,所以在图片上怎么调边距都没用。 - 以为
vertical-align能让块里的内容垂直居中 vertical-align只对行内元素和表格单元格生效,而且调的是元素在行盒里的位置,不是在父容器里的位置。想让一个块在容器里上下居中,要用 Flex、Grid 或定位。- 以为
vertical-align: middle是精确居中 middle对齐的是基线往上半个 x 高度,不是行盒的正中间。字体不同,x 高度不同,图片和文字看起来可能差一两像素。要严格居中,还是用 Flex 的align-items: center。
面试官还会怎么问?
inline-block 元素底部为什么也会不对齐?
inline-block 的基线是它最后一行文字的基线。里面有文字的和没文字的两个 inline-block 排在一起,基线位置不同,就会一高一低。给它们统一加 vertical-align: top 就能对齐。
表格单元格里的 vertical-align 有什么不同?
在 td 上,vertical-align 控制的是单元格内容在单元格里的上下位置,top、middle、bottom 就是字面意思的靠上、居中、靠底,和行内元素的规则不是一套。
用 Flex 排图片和文字,还会有这条缝吗?
不会。Flex 容器的子元素会变成 Flex 项目,不再是行内元素,行盒和支柱都不存在了,对齐改由 align-items 控制。这也是很多人觉得「用了 Flex 空白就没了」的原因。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。