淺談line-height和vertical-align

本文原創:liruifangcss

做爲一個前端人,常常混跡於圖片和文字相互糅雜的江湖中,稍有不慎便會中招,本文主要從line-height和vertical-align入手,分析項目中出現的「詭異」現象,透過現象看本質,從而化敵爲友爲我所用。html

目錄

  • 問題現象
  • 屬性介紹
  • 問題剖析
  • 簡單應用
  • 參考文獻

1、使人抓狂的現象

1. 單行文本佔據的高度
<style type="text/css">
    .demo1 {
        line-height: 100px;
        background-color: pink;
    }
    .demo1 span {
        font-size: 40px;
        background-color: grey;
    }
</style>
<div class="demo1">
    <span>xxJD-BG-FExx</span>
</div>
複製代碼

demo1.png

爲何單行文本的可視高度是109px,而不是100px?前端

2. 圖片下面的空隙
<style type="text/css">
    .demo2 {
        border: 1px solid black;
        width: 1080px;
    }
    .img {
        display: inline-block;
        height: 296px;
    }
    .text {
        background: pink;  
    }
</style>
<div class="demo2">
    <img  class="img" src="img/konan.jpg">
</div>
複製代碼

img-gap.png

圖片下方爲何會出現空隙?html5

3. 圖文對齊問題
<style type="text/css">
    .demo3 {
        font-size: 40px;
    }
    .icon {
        width: 1em;
        vertical-align: middle;
    }
    .gap {
        display: inline-block;
    }
    .gap span {
        /*vertical-align: middle;*/
    }
</style>
<div class="demo3">
    <p class="gap"><img class="icon" src="img/unpaid.png">待支付:</p>
</div>
複製代碼

img-text-1.png

明明用了vertical-align: middle,圖片位置爲何偏下?segmentfault

4. 矩形塊對齊異常
<style type="text/css">
    .demo4 {
        display: inline-block;
        width: 100px;
        height: 100px;
        border: 1px solid red;
    }
    .align {
        /*line-height: 0;*/
        /*font-size: 0;*/
    /*    vertical-align: top;*/
    }
</style>
<div class="demo4"></div>
<div class="demo4"></div>
<div class="demo4">x見證奇蹟x</div>
複製代碼

juxing.png

矩形塊爲何不是一行排列?bash

5.vertical-align怪異反應
<style type="text/css">
    .ctn-block{
        background-color: #bbb;
    }
    .ctn-block .child {
        display: inline-block;
        width: 100px;
        background-color: aliceblue;
    }
    .ctn-block .child-1 {
        height: 100px;
        vertical-align: middle;
    }
    .ctn-block .child-2 {
        height: 200px;
    }
    .ctn-block .child-3 {
        height: 300px;
    }
</style>
<div class="ctn-block">
    <div class="child child-1"></div>
    <div class="child child-2"></div>
    <div class="child child-3"></div>
</div>
複製代碼

noMiddle.png

最小矩形塊明明設置了vertical-align: middle;爲何沒有居中對齊,反而感受「掉」下去了?wordpress

2、透過現象看本質

(一)line-height

  • 本頁內容來自W3C:

www.w3school.com.cn/cssref/pr_d…佈局

  • 定義和用法

line-height 屬性設置行間的距離(行高)字體

  • 註釋

不容許使用負值ui

  • 說明

a.該屬性會影響行框的佈局。在應用到一個塊級元素時,它定義了該元素中基線之間的最小距離而不是最大距離。 b.line-height 與 font-size 的計算值之差(在 CSS 中成爲「行間距」)分爲兩半,分別加到一個文本行內容的頂部和底部。能夠包含這些內容的最小框就是行框。

  • 取值
取值 描述
normal 默認。設置合理的行間距。
number 設置數字,此數字會與當前的字體尺寸相乘來設置行間距。
length 設置固定的行間距。
% 基於當前字體尺寸的百分比行間距。
inherit 規定應該從父元素繼承 line-height 屬性的值。
  • 劃重點

a.分紅兩半加到文本行上下 b.相對值:相對於font-size計算

font-size: 14px;
line-height: 1.5;(21px)
line-height: 150%;
line-height: 1.5em;
複製代碼

都是21px,三者是否徹底同樣?

<head>
	<title>line-height相對值</title>
	<style type="text/css">
		body,h3,p {
			margin: 0;
		}
		body {
			font-size: 14px;
			line-height: 1.5;
			/*line-height: 150%;*/
			/*line-height: 1.5em;*/
		}
		h3 {
			font-size: 32px;
		}
		p {
			font-size: 20px;
		}
	</style>
</head>
<body>
	<h3>標題</h3>
	<p>內容</p>
</body>
複製代碼

上例中,vertical-align:1.5時,標題和文字顯示正常;其餘兩個值時,標題和文字卻擠在了一塊兒。

分析:繼承的差異,line-height爲數值時,全部子元素繼承的都是這個值;而另外兩個相對值,子元素繼承的是最終的計算值。

line-height.png

1. 對於塊級元素,line-height指定了元素內部行框盒子(line-boxes)的最小高度,對塊級元素自己沒有任何做用
2. 對於非替代純內聯元素,可視高度徹底由line-height決定(對,是徹底),line-height指定了用來計算行框盒子高度的基礎高度
3. 對於替代行內元素,例如img、input、button,line-height沒有影響
複製代碼

例子1

<div class="demo">
    <img src="img/konan.jpg">
</div>
.demo {
    line-height: 256px;
}
.demo img {
    height:128px;
}
複製代碼

分析:根據以上規則,line-height對塊級元素自己沒有任何做用,指定的是內部行框盒子的最小高度,而本例中內部是替代行內元素,line-height對其沒有影響,那麼,最外層div的可視高度是多少?128px!是256px

strut(直譯:支撐物)

  • 存在的前提:必須是html5聲明

  • 規範中的定義: 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 」struct"。

  • 解釋:每個行框盒子開始的位置都有一個與之行高、字體大小相同,寬度爲零的內聯盒子。===> 行框前面有一個寬爲0的空字符 ===>幽靈空白節點(張鑫旭大師命名)

例子2

<div class="demo">
    <span>此處是一行文字</span>
</div>
case1
    .demo {
        line-height: 96px;
    }
    .demo span {
        line-height: 20px;
    }

case2
    .demo {
        line-height: 20px;
    }
    .demo span {
        line-height: 96px;
    }
複製代碼

以上兩種狀況下,最外層div的可視高度是多少?都是96px

總結
  • 行框盒子的高度是由高度最高的那個內聯盒子決定的
  • 注意」幽靈空白節點「

那麼問題來了,若是是圖文混雜的混合的行框盒子,高度如何表現?

只能決定最小高度,最終高度說了不算

why?

1.替代行內元素不受控制 2.vertical-align的影響

(二)vertical-align

  • 本頁內容來自W3C

www.w3school.com.cn/cssref/pr_p…

  • 定義和用法

vertical-align 屬性設置元素的垂直對齊方式。

  • 說明

1.該屬性定義行內元素的基線相對於該元素所在行的基線的垂直對齊。 2.容許指定負長度值和百分比值。這會使元素下降而不是升高。 3.在表單元格中,這個屬性會設置單元格框中的單元格內容的對齊方式。

  • 取值
取值 描述
baseline 默認。元素放置在父元素的基線上
sub 垂直對齊文本的下標
super 垂直對齊文本的上標
top 把元素的頂端與行中最高元素的頂端對齊
text-top 把元素的頂端與父元素字體的頂端對齊
middle 把此元素放置在父元素的中部
bottom 把元素的頂端與行中最低的元素的頂端對齊
text-bottom 把元素的底端與父元素字體的底端對齊
length
% 使用 line-height的百分比值排列,容許負值
inherit 規定應該從父元素繼承 vertical-align 屬性的值
  • 劃重點

a. 做用前提:只應用於內聯元素以及display: table-cell的元素;好比float和position:absolution會使元素塊級化,沒有理由和vertical-align同時出現 b.相對值:相對於line-height計算 c.基線爲什麼物? d.父元素的中部指的是?

問題一:基線
  • 字母x的下邊緣就是咱們的基線:

baseline.png

  • 小寫字母'x'衍生出了"x-height"概念,指的的是小寫字母x的高度,在css中用ex來表示這個相對單位

  • baseline肯定規則:

1.inline-table元素:table第一行的baseline 2.父元素line box:最後一個inline box 的baseline 3.純文本的內聯元素:字符x的下邊緣 4.替換元素:替換元素的下邊緣 5.inline-block: (1) 內部沒有內聯元素,或者overflow不爲visible,則:baseline是該元素margin底邊緣 (2) 內部有內聯元素,baseline是元素裏面最後一行內聯元素的基線

問題二:父元素的中部
  • vertical-align: middle; 把此元素放置在父元素的中部

內聯元素:元素的垂直中心點和行框盒子基線往上1/2 x-height處對齊,即字符x的中心交叉位置點。 table-cell:單元格盒子相對於外面的表格行居中對齊。

middle.png

3、真相只有一個(解決最初的問題)

  • 嫌疑人:line-height,vertical-align,幽靈空白節點

  • 突破口: line-box的基線,在哪裏? inline級元素的基線,在哪裏? line box先後打個小寫字母「x」瞧瞧

現象一:單行文本佔據的高度

demo1.png

  • 分析:對於字符而言,font-size越大,基線位置越往下,由於文字默認所有是基線對齊,字號不一致的文字在一塊兒,會發現上下位移。

myFont.png

  • 解決辦法: 「幽靈空白節點」的字體和後面span的字體同樣大 改變垂直對齊方式,如:vertical-align:top等

現象二:圖片間隙問題(inline元素的水平垂直空隙,常見:img、li等)

  • 水平空隙是由於換行引發的,這個換行會變成一個空白,這個空白會被解析爲DOM中的文本節點
  • 垂直空隙:三大元兇

img-gap.png

  • 分析

vertical-align默認值是baseline, 也就是基線對齊。 「幽靈空白節點」的高度是由行高決定的

  • 解決辦法

經過display或者position,float等將inline水平的img變成block,一口氣幹掉三個元兇 使用其餘vertical-align值 直接修改line-height值:下面的空隙高度,其實是文字計算後的行高值和字母x下邊緣的距離。所以,只要行高足夠小,實際文字佔據的高度的底部就會在x的上面,下面沒有了高度區域支撐 line-height爲相對單位,font-size間接控制

現象三:圖文對齊表現

img-text.jpg

  • 分析

沒有通過處理的文字,其基線和line box的基線重合,圖片設置vertical-align:middle,其正中心對準父級元素的x的正中心; 可是x字母的正中心並非其所在的text-box的正中心,而是text-box中心稍稍的偏下了一點

  • 解決辦法

咱們把「center」包裹起來併爲也設置 vertical-align: middle,「center」的基線就再也不和line-box的基線重合了,而是稍稍下移了,圖文對齊 利用margin-bottom處理 利用vertical-align: length(負值), 設置數值進行對齊 尺寸合適的狀況下,能夠採用1ex的方式(經驗取值基於20px的圖標)

現象四:矩形塊對齊異常

juxing.png

  • 分析

根據基線的肯定規則,框裏沒有內聯元素的,基線是容器的margin下邊緣,框內有文字的,基線是文字的基線:字母x的下邊緣;所以:左框下邊緣與右框x字符底邊對齊

  • 解決辦法

line-height:0;或者font-size:0;(間隔更大,why?提示:line-height爲0,字符佔據的位置也爲0,高度的起始位置變成字符內容框的垂直中心位置[存在字符下沉],字符上移,基線也上移) 換一種對齊方式,vertical-align設爲其餘值

現象五:vertical-align:middle讓元素下移而不居中

noMiddle.png

  • 分析

middle對齊的參照標準是將子元素盒子的垂直中點與父盒子的baseline加上父盒子的x-height的一半位置對齊

  • 解決辦法

一種方式是將最高的元素設爲vertical-align:middle,而後將想要居中的也設定爲vertical-align:middle (解釋)最高元素設定爲vertical-align:middle後,這個元素對於line box來講,baseline就是其中線,再將須要設定垂直居中的元素也設定爲vertical-align:middle,它們的baseline必然在最高元素的baseline之上,因此被強制下移,進行居中。

4、化敵爲友(簡單的應用)

(一)不受字體字號影響的內聯元素的垂直居中對齊效果:

內聯元素默認是基線對齊的,而基線就是x的底部,而1ex就是一個x的高度。設想下,假如咱們圖標高度就是1ex, 同時背景圖片居中,豈不是圖標和文字自然垂直居中,並且,徹底不受字體和字號的影響。由於ex就是一個相對於字體字號的單位。

<div>
    liruifang<i class="icon-arrow"></i>
    京東前端<i class="icon-arrow"></i>
</div>
<style type="text/css">
    .icon-arrow {
        display: inline-block;
        width: 20px;
        height: 1ex;
        background: url(img/arrow.png) no-repeat center;
    }
</style>
複製代碼

(二)垂直居中

  • 單行文字:line-height設置爲須要的高度便可,不須要設置height,若是設置則二者須要保持同樣。
  • 多行文字:高度固定,文字單行或者多行,字體有大有小,如何居中?(提示:利用幽靈空白節點,與圖片居中相似)
  • 圖片:利用幽靈空白節點響應line-height造成高度,此時,圖片再來個vertical-align:middle,就能夠和這個被行高撐高的幽靈空白節點(近似)垂直對齊了。
  • 近似的緣由:字符x的位置都是偏下一點的
    middle-1.png
  • 徹底居中:font-size:0,絕對中心線和中線重合。

(三)利用line-block和基線多變之間的關係:處理圖文對齊

  • 例如,實現一個刪除的圖標(delete.html)
<i class="icon-delete"></i>刪除
<i class="icon-delete">刪除</i>(爲了使得文字不可見,設置overflow:hidden)
複製代碼
  • 分析:空標籤 or overflow:hidden 基線是底邊緣,與文字默認不對齊

  • 思路:圖標和文字高度一致 + 基線一致 = 對齊!

  • 圖標和當前高度都是20px:如需合併背景圖標,做者建議圖標原圖統一處理成一種規格再進行合併
  • 圖標標籤裏永遠有文字:藉助:before或者:after僞元素生成一個空格字符
  • 潛在字符不可見,可是不使用overflow:hidden,保證基線爲裏面字符的基線
<style type="text/css">
    .box {
        line-height: 20px;
    }
    .icon {
        display: inline-block; 
        width:20px; 
        height:20px; 
        white-space: nowrap; 
        letter-spacing: -1em; 
        text-indent: -999em;
    }
    .icon:before {
        content:'\3000';
    }
    /* 具體圖標 */
    .icon-xxx {
        background: url(img/delete.png) no-repeat center;
    }
</style>
<div class="box">
    <h4>1. 空標籤後面跟隨文本</h4>
    <p><i class="icon icon-delete"></i>刪除</p>
    <h4>2. 標籤裏面有「刪除」文本</h4>
    <p><i class="icon icon-delete">刪除</i>看一眼時間</p>
</div>
複製代碼
  • 優點:
  • 不須要margin和vertical-align的垂直偏移
  • 小圖標和文字對齊徹底不受字體大小影響
  • 整個項目小圖標和文字對齊的問題均可以解決,節約css代碼,下降開發和維護成本
  • 說明:20px是經驗取值,若是項目設計很大氣,例如字號默認16px, 能夠改爲24px(詳見《css世界》)

myFont.png

現象問題(使人抓狂)——> 屬性介紹(透過現象看本質)——> 問題剖析(真相只有一個)——> 簡單應用(化敵爲友)

5、參考文獻

相關文章
相關標籤/搜索