深入行高 - line-height和inline元素的排版

上一篇中提到自己 debug 時遇到一個 css 知識盲點:行高和字體的關系。隨后查了相關資料,在這里梳理下這個知識,最后解釋下產生這個現(xiàn)象的原因。

現(xiàn)象

一般我們要讓文字在容器中產生垂直居中的效果,會把容器高度和行高設置成一樣,來達到這個效果(代碼,效果圖如下)。

<div style="height:32px; line-height:32px; border:1px solid black;">
  <span>Test<span>
</div>
ih-pic1.png

但是當容器的字體大小和文字的字體大小不一致的時候,字體就無法居中了(代碼,效果圖如下)。

<div style="height:32px; line-height:32px; border:1px solid black; font-size:42px">
  <span style="font-size:20px;">Test<span>
</div>
ih-pic2.png

原理概述:行內元素如何排版

在解釋上述現(xiàn)象之前,我們先來看下行內元素(inline-element)在頁面上是如何排版的。我們先假設頁面上沒有任何我們添加的 css,每個行內元素會占據一定的矩形空間,我們稱之為行內框(inline-box),如下圖和代碼:

<div style="border:1px solid black; color:white;">
  <span>span</span> <em>em</em> <strong>I am very very very very very very strong</strong>
</div>
ih-pic3.png

span em strong 都是行內元素,背景顏色標出了它們行內框所占的空間(這里只是為了圖示方便,用顏色標示了行內框占據的大致空間,因為 css 中并沒有給行內元素的行內框設置顏色的屬性)。而如果沒有用行內元素包裹的文字呢?瀏覽器會給文字生成一個匿名的行內框,如下圖ih-pic3.png 中用綠色框框出來的所示。

<div style="border:1px solid black; color:gray;">
  anonymous <span>span</span> <em>em</em>
</div>
ih-pic4.png

上面兩個例子字體都是統(tǒng)一大小的,如果每個行內元素字體不一樣大小呢?每個行內框會根據各自的 vertical-algin 在垂直方向上對齊,我們先看下示例(示例中每個行內元素的 vertical-algin 都設置成一樣,但是每個元素的 vertical-algin 也可以各自不同,這里我就省略了各自不同的例子):

<style>
  span { font-size: 32px; }
  em { font-size: 20px; }
  strong { font-size: 16px; }
  .vertical-align-wrapper * {
    vertical-align: top; /* 對應的是圖ih-pic5.png */
    /* vertical-align: middle; 對應的是圖ih-pic6.png*/
    /* vertical-align: baseline; 對應的是圖ih-pic7.png*/
    /* vertical-align: bottom; 對應的是圖ih-pic8.png*/
  }
</style>
<div class="vertical-align-wrapper" style="border:1px solid black; color:gray;">
  anonymous <span>span</span> <em>em</em> <strong>I am very very very very very very strong</strong>
</div>
ih-pic5.png
ih-pic6.png
ih-pic7.png
ih-pic8.png

如果一行中的行內元素字體大小和 verticial-align 各不相同,那么整個一行占據空間是如何算的呢?這一行的高度最高處由垂直方向上行內框最高的元素決定,最低處由垂直方向上行內框最低的元素決定(代碼,圖如下):

<style>
  span { font-size: 30px; vertical-align: top; }
  em {  font-size: 30px; vertical-align: top; }
  strong {  font-size: 30px; vertical-align: top; }
</style>
<div style="border:1px solid black; color:gray; vertical-align: bottom;">
  anonymous <span>span</span> <em>em</em> <strong>I am very very strong</strong>
</div>
ih-pic9.png

圖ih-pic9.png 中黃色框表示的就是整行占據的空間,我們稱之為行框(line-box)。再給一個帶上下標的示例看看是如何計算行框占據的空間(還是黃色框占據的空間表示行框):

<div style="border:1px solid black; color:gray; vertical-align: bottom;">
  anonymous <span>span</span><sup>sup</sup> <em>em</em><sub>sub</sub> <strong>I am very very strong</strong>
</div>
ih-pic10.png

所以行內元素字體大小決定了字的大小,每個行內元素占據的空間又由行內框(inline-box)決定,最后一整行如果只有行內元素,則所占據的空間就是行框(line-box)決定的,高度亦是行框的高度。如果文字很長折成了多行,那么每行都是按照以上規(guī)則生成多個行框,并在垂直方向上以容器內部邊界的左上角開始向下排列:

ih-pic11.png

接下來我們就要看下 line-height 是怎么影響元素的了。剛剛我們提到一個行內元素占據的空間叫行內框,那么行內框的高度是如何決定的呢?就是 css 屬性行高(line-height)決定,瀏覽器通常全局的默認行高是 normal,約等于字體的1.2倍。譬如一個行內元素的字體是 12px,那么行高就是 12 x 1.2 = 14.4(px)。而行高和字體間的距離差距我們叫做 leading(中文可以叫做行間距,不過網頁上的行間距和傳統(tǒng)印刷業(yè)的行間距代表的地方不同,這里就不描述其歷史和不一樣的地方了)。瀏覽器會把 leading 除以二,平均放到字體的上面和下面,這兩塊平均空間的距離叫做 half-leading,如下圖(圖中為了演示明顯,字體大小設為 16px,行高設為 32px):

ih-pic12.png

如果 line-height 小于字體大小,那么行內框的高度就會向字體的中心線收縮,字體將會溢出行高,如下圖(圖中為了演示明顯,字體大小設為 32px,行高設為 20px):

ih-pic13.png

行內框的高度會影響行框的高度,我們假設極端情況每行只有一個行內元素,那么每行行框(line-box)的高度就是這個元素行內框(inline-box)的高度,讓我們看看多行情況下行高(line-height)大于字體和小于字體產生的效果,溢出行高的字體將在多行垂直方向疊加:

ih-pic14.png

最后我們說下如果手工設置了元素的 line-height,將如何影響元素:

  1. 行內元素設置 line-height 等于指定了行內框的高度。
  2. 沒有行內元素包裹的文字所生成的匿名行內框的高度是繼承自它的父容器。
  3. 塊級元素包裹了一系列行內元素,這些行內元素自己沒有設置 line-height,那么給塊級元素設置 line-height 等于給被包裹的行內元素指定了最小行內框的高度。

現(xiàn)象產生原因分析

一般情況:

<div style="height:32px; line-height:32px; border:1px solid black;">
  <span>Test<span>
</div>

div 設置的 line-height:32px 給 span 限定了行內框的最小高度,而 span 的默認行高和字體都沒有超過 32px,所以 span 的行內框高度就是 32px,又因為 half-leading 平均分配的原理,那么字體就會在行內框中居中,如果一行字行內框高度相同,那么整行文字的行框高度就是 32px,最后 div 的高度又設置了 32px,所以最后文字看起來是垂直居中的。(其實如果以此例來說 div 不設置高度也沒有問題,因為 div 高度就是按內部元素高度而撐開的)

異常情況:

<div style="height:32px; line-height:32px; border:1px solid black; font-size:42px">
  <span style="font-size:20px;">Test<span>
</div>

雖然看上去 div 只有一個子元素 span,但是從規(guī)范上我得知,這種情況下有一個寬度無限小的匿名行內框存在。如果在 div 上設置了字體 42px,那么這個匿名行內框的字體就變成了 42px,且 div 的 line-height 只能指定匿名行內框的最小高度,當匿名行內框的字體大于 32px 時,這個匿名行內框的高度就變大超過了 32px,最后導致整行的行框高度超過 32px。而 span 的行內框和字體雖然都沒有超過 32px ,但是它的 baseline 需要在水平方下沉和這個匿名行內框對齊,但是 div 的高度限制成了 32px,最后看上去 span 就不在垂直居中的方向上了。

參考資料

  1. https://www.slideshare.net/maxdesign/line-height
  2. https://www.w3.org/TR/REC-CSS2/visuren.html#inline-formatting
  3. http://www.zhangxinxu.com/wordpress/2009/11/css%E8%A1%8C%E9%AB%98line-height%E7%9A%84%E4%B8%80%E4%BA%9B%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E5%8F%8A%E5%BA%94%E7%94%A8/
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容