深入理解 line-height 和 vertical-align
幾個概念
- line box:包裹 inline box 的一個盒子,一個或多個 line box 堆疊撐起一個 HTML 元素。
- inline(-level) box:可以是一個由行內(nèi)元素包裹的盒子,也可以是一個純文字的匿名盒子。
- content area:對于非替換元素來說,content area 的范圍由 font-size 以及字體本身決定;對于替換元素來說,由元素自有寬高決定。
- baseline:一個元素基線的位置由該元素內(nèi)字母 x 底部所在的位置決定,當(dāng)然字體不同基線所在的位置也就不同。
通過一段代碼可以理解一下:
div {
background-color: #ccc;
font-size: 20px;
color: #fff;
}
span {
color: red;
}
<div>文字1<span>文字2</span>文字3</div>

白色的文字就是一個匿名 inline box,紅色的文字是一個由 span 包裹的 inline box。這三個 inline box 組成一個 line box,可以理解為灰色的區(qū)域,因為在這個例子里就是由一個 line box 撐開了 div。如果有多行的文字,那就有多個 line box。
關(guān)于 content area,W3C 有一段這樣的解釋:
CSS 2.1 does not define what the content area of an inline box is (see 10.6.1 above) and thus different UAs may draw the backgrounds and borders in different places.
這篇文章對非替換元素 content area 的定義就是自有寬高加上 margin,padding 以及 border。我認為應(yīng)該將 content area 理解為 content box。
line box 高度
瀏覽器會計算 line box 中每一個 inline box 的高度,對于不同的 inline box 計算方式有所不同:
如果是一個替換元素(比如 img,input),inline-* 元素或者是 flexbox 中的子元素,高度由其 margin box 決定;
inline-block 元素:
div {
background-color: #ccc;
color: #fff;
}
span {
display: inline-block;
height: 30px;
margin: 10px;
background: #fff;
color: red;
}
<div>xxx<span>xxx</span>xxx</div>

這里 span inline box 的高度就是 height + margin 2。如果 height 的值是 auto,高度就是等于 line-height + margin 2。
如果是一個非替換元素,高度由它的 line-height 決定,而不是 content area,雖然有時候看起來像 content area 撐開了 line box 的高度。
div {
background-color: #ccc;
font-size: 20px;
color: #fff;
font-family: Sana;
}
span {
background: #fff;
color: red;
}
<div>xxx<span>xxx</span>xxx</div>

這張圖片可以明顯地看出撐開 line box 的是 line-height,而不是 content area。
這篇文章用了 virtual-area height 來表示 line-height 撐開的高度,而我的理解其實就是 inline box 的高度。
line box 中所有 inline box 的最高點以及最低點決定了它的高度(該計算包括了 strut 的高度,后文會提到 strut)。
非替換元素的的 margin,padding 以及 border 并不會影響 line box 高度的計算。當(dāng)一個 inline-level box 的 line-height 小于 content area 的時候,line box 的高度就會小于 content area,此時元素的 background 以及 padding 等就會溢出到 line box 之外。
以下代碼可以說明這個問題:
div {
background: #eee;
border: 1px solid #000;
box-sizing: border-box;
font-size: 50px;
line-height: 10px;
}
span {
background: red;
margin: 10px;
padding: 10px;
}
<div><span>xxx</span></div>

leading:
content area 的高度與 inline box 的高度差就是 leading,這個 leading 會等分被添加到 content area 的頂部與底部,所以說 content area 永遠位于 inline box 的中間(垂直居中)。
strut:
瀏覽器認為每一個 line box 的起始位置都存在一個寬度為 0,沒有任何字符的 匿名 inline box,稱為 strut,這個 strut 是會從父元素繼承 line-height 的,因此它的高度會影響整個 line box 高度的計算。
一個例子

div { background: #eee; border: 1px solid #000; box-sizing: border-box; }
<div><img src="./image.png" alt=""></div>
在圖片中可以看到 img 與外層的 div 存在一個間隙,這就是上文提到的 strut 造成的。
在這個例子中,默認情況下 img 的底邊與父元素的基線對齊(img { vertical-align: baseline }),而這個基線實際上就是 strut 基線所在的位置。如下圖所示:

strut 其實就相當(dāng)于一個不可見的字母 x,上文已經(jīng)提到 strut 本身是具有 line-height 的,所以就導(dǎo)致圖片底部多了一段間隙。
總結(jié)一下存在間隙原因:
- strut 存在 line-height
- vertical-align 默認值為 baseline
對應(yīng)的解決方案:
- 修改 strut 的 line-height,因為 strut 的 line-height 不是能夠直接設(shè)置的,所以需要設(shè)置父元素的 line-height,然后讓 strut 繼承,或者修改 font-size
- 將 vertical-align 設(shè)置為其他值line-height
W3C 中對于 line-height 的解釋是這樣的:
On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if 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."
我的簡單理解是,對于由行內(nèi)元素組成的塊級元素而言,line-height 決定了 line box 的最小高度,瀏覽器會假定每一個 line box 以一個寬度為 0 的 inline box (strut)開始,而這個 strut 從父元素繼承到 font 以及 line-height。
- normal 是 line-height 的默認值,W3C 對它并沒有一個明確的定義。normal 會將 content area 作為一個計算因素。
- line-height 并不是兩條 baseline 之間的距離。
line-height的值推薦使用數(shù)值,而不是使用 em 單位,因為 em 單位會根據(jù)從父元素繼承到的font-size來計算行高。
vertical-align
W3C 對 baseline 以及 middle 的定義如下:
baseline: Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent's baseline.
元素基線與父元素基線對齊,如果元素沒有基線,比如 img,則使用 margin 底邊與父元素基線對齊。
middle: Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.
元素的垂直中點位置與父元素的基線加上一半 x-height 的位置對齊。
參考
Deep dive CSS: font metrics, line-height and vertical-align
https://meyerweb.com/eric/css/inline-format.html
https://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-height/
https://www.w3.org/TR/CSS2/visudet.html#inline-box-height
相關(guān)文章
- CSS Grid 是一種二維布局系統(tǒng),可以同時控制行和列,相比 Flex(一維布局),更適合用在整體頁面布局或復(fù)雜模塊結(jié)構(gòu)中,這篇文章主要介紹了前端CSS Grid 布局詳解,需要的朋2025-04-16
CSS Padding 和 Margin 區(qū)別全解析
CSS 中的 padding 和 margin 是兩個非?;A(chǔ)且重要的屬性,它們用于控制元素周圍的空白區(qū)域,本文將詳細介紹 padding 和 margin 的概念、區(qū)別以及如何在實際項目中使用它們2025-04-07- will-change 是一個 CSS 屬性,用于告訴瀏覽器某個元素在未來可能會發(fā)生哪些變化,本文給大家介紹CSS will-change 屬性詳解,感興趣的朋友一起看看吧2025-04-07
- 本文給大家分享在 CSS 中,去除a標簽(超鏈接)的下劃線的幾種方法,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧2025-04-07
在前端開發(fā)中,CSS(層疊樣式表)不僅是用來控制網(wǎng)頁的外觀和布局,更是實現(xiàn)復(fù)雜交互和動態(tài)效果的關(guān)鍵技術(shù)之一,隨著前端技術(shù)的不斷發(fā)展,CSS的用法也日益豐富和高級,本文將2025-04-07css中的 vertical-align與line-height作用詳解
文章詳細介紹了CSS中的`vertical-align`和`line-height`屬性,包括它們的作用、適用元素、屬性值、常見使用場景、常見問題及解決方案,感興趣的朋友跟隨小編一起看看吧2025-03-26淺析CSS 中z - index屬性的作用及在什么情況下會失效
z-index屬性用于控制元素的堆疊順序,值越大,元素越顯示在上層,它需要元素具有定位屬性(如relative、absolute、fixed或sticky),本文給大家介紹CSS 中z - index屬性的作用2025-03-21- 文章詳細介紹了CSS中的打印媒體查詢@mediaprint包括基本語法、常見使用場景和代碼示例,如隱藏非必要元素、調(diào)整字體和顏色、處理鏈接的URL顯示、分頁控制、調(diào)整邊距和背景等2025-03-18

CSS模擬 html 的 title 屬性(鼠標懸浮顯示提示文字效果)
本文介紹了如何使用CSS模擬HTML的title屬性,通過鼠標懸浮顯示提示文字效果,通過設(shè)置`.tipBox`和`.tipBox.tipContent`的樣式,實現(xiàn)了提示內(nèi)容的隱藏和顯示,感興趣的朋友一起2025-03-10
前端 CSS 動態(tài)設(shè)置樣式::class、:style 等技巧(推薦)
本文介紹了Vue.js中動態(tài)綁定類名和內(nèi)聯(lián)樣式的兩種方法:對象語法和數(shù)組語法,通過對象語法,可以根據(jù)條件動態(tài)切換類名或樣式;通過數(shù)組語法,可以同時綁定多個類名或樣式,此外2025-02-26




