【前端Talkking】CSS系列——CSS深入理解之line-height

micstone發表於2018-06-08

1.寫在前面

兩個多周的時間沒有寫文章了,手好癢好癢,趁著公司在裝修,從上週末到本週都在家辦公,同時公司的專案並不緊急,於是抽著時間梳理了一下CSS中關於行高line-height的理解,今天釋出出來,大家準備好了嗎?

2.基本概念

2.1行高的定義與圖解

行高,顧名思義指的就是一行文字的高度。按照定義來解釋,就是兩行文字之間基線之間的距離。那麼問題來了,什麼是基線呢?大家回想下我們剛開始學習漢語拼音的時候,使用四線格本子的四條線,其中倒數第二條線就是基線,如果你說,抱歉,我已經全部還給老師了,沒有任何印象。呵呵,別急呢,我已經給大家準備好了,請看下面的這副圖,其中,a、c、e、x、z等字母的底邊線(倒數第二根線)就是我們說的基線。

【前端Talkking】CSS系列——CSS深入理解之line-height

瞭解完基線的定義後,我們接著來聊行高line-height。上面我們說過,行高就是兩條基線的之間的距離,如下圖所示。

【前端Talkking】CSS系列——CSS深入理解之line-height

大家是不是已經?了,大家耐著性子仔細看下,其實挺好理解的:

  • 兩條紅線之間的距離就是行高(line-height)
  • 上一行的底線和下一行的頂線之間的距離就是行距,業界的共識是:行距=行高-em-box(暫時理解為font-size的大小),因此,用CSS語言來解釋行距就是: 行距=line-height-font-size。
  • 同一行頂線和底線之間的距離就是font-size
  • 行距的一半就是半行距

結合上面圖和文字描述,其實可以很容易搞清楚行高、行距、半行距、font-size的意思。大家一定要弄清楚這些定義,因為,下文中的內容和這些定義有關。

2.2 內容區、行內框、行框、包含框

所謂一圖勝千言:

【前端Talkking】CSS系列——CSS深入理解之line-height

內容區:內容區域可以近似理解為FireFox/IE瀏覽器下文字選中帶背景的區域,在上圖中,深灰色背景區域就是內容區域。

行內框:每一個行內元素都會生成一個行內框,高度等於font-size,當我們設定line-height的時候,行內框的高度保持不變,改變的是行距的高度。

行框:指本行的一個虛擬的矩形框,由本行中的行內框組成。當有多行內容的時候,每一行都有自己的的一個行框。

包含框: 包裹著上述三種box的box,暈了,直接看圖吧,上面黃顏色的框就是包含框。

3.深入理解line-height

3.1 line-height的各類屬性值

line-height的預設值是normal,同時還支援數值、百分比值、長度值、繼承。請看下面的表格:

描述
normal 預設。設定合理的行間距。
number 設定數字,此數字會與當前的字型尺寸相乘來設定行間距,即number為當前font-size的倍數。
length 設定固定的行間距。
% 基於當前字型尺寸的百分比行間距。
inherit 規定應該從父元素繼承 line-height 屬性的值。
  • normal

大家在使用line-height的時候,設定為該值很少,為什麼呢?因為normal是一個與font-family有著密切聯絡的變數值。例如:

div{
    line-height: normal;
    font-family: 'microsoft yahei';
}
複製程式碼

div{
    line-height: normal;
    font-family: 'simsun';
}
複製程式碼

這兩段程式碼在不同瀏覽器中測試資料如下:

字型 Chrome Firefox IE
微軟雅黑 1.32 1.321 1.32
宋體 1.141 1.142 1.141

從上面的表格中可以看到,指定字型後,在不同瀏覽器中line-height的解析值基本是一樣的。然而,不同的瀏覽器使用的預設字型不一樣,並且不同的作業系統使用的預設字型也是不一樣的。因此,我們在實際開發的時候,都需要對行高line-height進行重置操作。

  • inherit

    字面意思是繼承,即繼承父元素line-height的值,父元素是多少,當前節點的line-height就是多少,如果當前節點的子節點不設定任何的line-height,子節點的line-height也是這個值。

  • length

    也就是帶單位的值,比如line-height: 21pxline-height: 1.5em等。如果當前的font-size為14px,則line-height計算後的值為1.5*14px=21px

  • number

    例如,line-height: 1.5,最終的計算值是和當前的font-size相乘後的值,比如font-size為14px,則line-height計算值是1.5*14px=21px

  • %

    例如,當前font-size為16px,line-height為120%,則計算後的行高為16*120%=19.2px

不知道大家發現沒有,line-height:1.5line-height: 150%以及line-height: 150%這三種用法計算的結果 是一樣的,最終計算的行高都是根據font-size來計算的。是不是它們可以相互替代呢?其實不然,實際上,line-height:1.5和另外兩個的繼承細節有些區別,我們直接看例子吧。

body{
    font-size: 14px;
    line-height: 1.5;
}
body{
    font-size: 16px;
    line-height: 150%;
}
body{
    font-size: 14px;
    line-height: 1.5em;
}
複製程式碼

對於<body>元素而言,上面三種方式計算後的的行高都是21px,但是,如果body下還有子元素,例如:

<body>
    <h3>這是標題</h3>
    <p>這是內容</p>
</body>
複製程式碼
h3, p{
    margin: 0;
}
h3{
    font-size: 32px;
}
p{
    font-size:  20px;
}
複製程式碼

最終結果是line-height: 150%line-height: 1.5em的最終表現是兩行文字重疊到了一起,如下圖:

【前端Talkking】CSS系列——CSS深入理解之line-height

而設定了line-height:1.5的最終表現是兩行文字沒有重疊,排版良好,效果如下圖:

【前端Talkking】CSS系列——CSS深入理解之line-height

設定line-height: 150%line-height: 1.5em後,子元素繼承的是計算後的值,即21px,而不是繼承150%和1.5em,所以<h3><p>的行高都是21px,而<h3>的font-size是32px,則根據上面的公式計算出來的半行距是-5.5px,因此,兩行文字發生了重疊。

不同屬性下的line-height最終的計算方式比較如下。

設定方式 line-height 計算後的line-height 子元素繼承的line-height
inherit 父元素的line-height值 不用計算 父元素的line-height值
length 20px 不用計算 20px
% 150% 自身font-size (14px) * 150% = 21px 繼承父元素計算後的line-height值 21px,而不是150%
normal 假如為1.2 自身font-size (16px) * 1.2 = 19.2px 繼承1.2,line-height = 自身font-size(32px) * 1.2 = 38.4px
純數字 1.5 自身font-size (14px) * 1.5 = 21px 繼承1.5,line-height = 自身font-size(32px) * 1.5 = 48px

所以,在實際開發中, 我們一般設定行高的值為 `純數字是最推薦的方式,因為其會隨著對應的 font-size 而縮放,排版效果良好。

3.2 line-height的"大值特性"

現在,請大家仔細閱讀下面的程式碼:

<div class="box">
    <span>這是內容...</span>
</div>
複製程式碼
.box{
    line-height: 50px;
}
.box span{
    line-height: 10px;
}
複製程式碼

.box{
    line-height: 10px;
}
.box span{
    line-height: 50px;
}
複製程式碼

丟擲問題:請問div的高度是多少?直接上正確答案:都是50px。請看圖

【前端Talkking】CSS系列——CSS深入理解之line-height

感覺說不通啊,那麼請看解釋吧。

首先,我們要始終記著,內聯元素前面有一個看不見的"幽靈空白節點",因此,上面的html程式碼可以等價為:

<div class="box">
    幽靈空白節點<span>這是內容...</span>
</div>
複製程式碼

所以,當.box元素設定line-height:50px的時候,"幽靈空白節點"高度為50px,而當.box元素設定line-height: 20px的時候,span元素的高度變成了50px,而又因為行框盒子是由高度最高的那個內聯盒子決定的,所以.box元素的高度永遠是最大的那個line-height的原因,根據張鑫旭老師的總結,這可以稱為line-height的大值特性,不知道這樣解釋大家清楚了沒有呢?

3.3 line-height與內聯元素"垂直居中"

  • 行高讓單行文字"垂直居中"

不知道你是否和我一樣,在剛開始寫CSS的時候,控制單行文字垂直居中的時候,設定line-heightheight的值一樣就可以實現文字垂直居中的效果,即:

.title{
    height: 50px;
    line-height: 50px
}
複製程式碼

其實,這裡只需要保留line-height這個屬性就可以了,完全沒有任何必要設定height的大小。

<div style="height: 50px; background-color: #cd0000; color: #fff">
    <span style="line-height: 50px">元素元素元素</span>
</div>
複製程式碼

【前端Talkking】CSS系列——CSS深入理解之line-height

因此,流傳比較廣的"設定line-heightheight的值一樣就可以實現文字垂直居中效果", 應該修改為:把line-height設定為您需要的box的大小可以實現單行文字的垂直居中

  • 行高讓多行文字“垂直居中”

多行文字垂直居中效果需要藉助line-height的好朋友的幫助才能實現,程式碼如下:

<div class="box">
    <div class="content">基於行高是實現的多行文字垂直居中...我發現文字很短,於是隨便寫了一點文字湊個數..</div>
</div>
複製程式碼
.box{
    line-height: 120px;
    background-color: #cd0000;
    color: #fff;
}
.content{
    display: inline-block;
    line-height: 20px;
    margin: 0 20px;
    vertical-align: middle;
}
複製程式碼

效果圖如下所示:

【前端Talkking】CSS系列——CSS深入理解之line-height

實現的原理如下:

  1. 多行文字使用一個標籤包裹,同時設定display: inline-block,保持了內聯元素的特性,使元素具有單行效果,該設定使元素形成了一個非常關鍵的"行框盒子",而每一個行框盒子都會附帶一個"幽靈空白節點"(寬度為0,但是表現和普通字元相同)。而我們設定了外層的line-height: 120px,因此,.content內容"幽靈空白節點"的line-height也將是120px;
  2. 內聯元素預設是基線對齊的,通過設定vertical-align:middle可以實現我們想要的"垂直居中"效果。

3.4 真的是"垂直居中"嗎

不知道大家有沒有留意上文中的單行文字和多行文字的垂直居中都加了引號,難道還不是真正的垂直居中?沒錯,line-height實現的垂直居中效果只是近似的垂直居中。為什麼是"近似"?我們拿一個例子說明問題:

<p>微軟雅黑</p>
複製程式碼
p{
    font-size: 80px;
    line-height: 120px;
    background-color: #cd0000;
    color: #fff;
    font-family: "Microsoft YaHei";
}
複製程式碼

在瀏覽器中(windows系統)的效果如下:

【前端Talkking】CSS系列——CSS深入理解之line-height

大家看到沒有,這些文字的位置明顯偏下。因為,有些字型的位置偏下,比如"微軟雅黑",在平時我們使用的過程中,字型大小基本在16~18px之間,雖然下沉,但是也就是1px的偏差,我們的肉眼根本察覺不到。因此,使用line-height實現的"垂直居中"並不是絕對的垂直居中

同理,使用line-heightvertical-align實現的多行文字垂直居中也不是絕對的垂直居中,在上文中多行文字垂直居中的例子中,我們可以明顯的看到字型位置偏下。

其實,不居中並不是line-height導致的,而是他的好基友vertical-align造成的,我們會在vertical-align文章中詳細闡述,敬請期待。

4. 最後

關於line-height的介紹就到這裡了,平時我們應該多思考,多總結,才會有新的體會。以後我的最新文章都會第一時間更新在公眾號<前端Talkking>裡面,歡迎大家關注。

以上就是本文的全部內容,感謝閱讀,如果有表述不正確的地方,歡迎留言指正!?

ps:這兩天是一年一度的高考,想想自己的高考差不多過去了10年了,而現在自己好像沒有什麼成就,想想好慚愧,努力吧,少年!!!

參考


遇見了,不妨關注下我的微信公眾號「前端Talkking」

【前端Talkking】CSS系列——CSS深入理解之line-height

相關文章