CSS魔法堂:深刻理解line-height和vertical-align

前言

一直據說line-height是指兩行文本的基線間的距離,而後又說行高等於行距,最近還據說有個叫行間距的傢伙,@張鑫旭還說line-height和vertical-align基情四射,貴圈真亂啊。。。。。。因而經過本篇來一探究竟:)javascript

line-height到底有多height?

行距、行間距傻傻分不清

 首先看看「有道詞典」的解析!css

Leading = Line Space + Font Size(便是 行距 = 行間距 + 字體大小)
Leading: 指相鄰文本行間上一個文本行基線和下一文本行基線間的距離。
Line Space: 指相鄰文本行間上一個文本行下行線(ascent)和下一文本行上行線(descent)間的距離。html

而在一些面向普通消費者的軟件中,Leading每每是指Line Space。Leading
 在CSS當中,Leading就是指Line Space。而CSS屬性line-height則是用於設置真實的Leading。參考java

Still for each glyph, determine the leading L to add, where L = 'line-height' - ADnode

AD是指字形ascent和descent間的距離,便是font-size。
 這裏爲更清晰地敘說,我將以廣義Leading指代行間距,而狹義Leading則指代行距。
從W3C Rec中看出,line-height就是狹義Leading,而line-height的字面意思即爲「行高」,推導結果CSS中行高便是行距。
這裏咱們瞭解到行高行距行間距的區別了。那接下來要介紹line-height的一個重要特性——垂直居中性。chrome

line-height的垂直居中性

 經過L = 'line-height' - AD咱們知道line-height=行間距+字形大小,字形大小咱們能夠經過font-size來設置,而line-height就更不用說了,而家問題是行間距所佔的空間是怎樣分配的呢?
方案1:不是說行間距就是上一行的descent到下一行的ascent間的距離嗎?那直接分配到A位置就行了。

方案2:若是方案1的分配方案合理,那麼分配到B位置就也是OK的。

方案3:一邊倒的分配方案太不美觀了吧!不如將行間距對半開,而後分別分配到上下兩端不就OK了嗎!

CSS採用的就是方案3。這是引用了Half-leading的概念,Half-leading = Leading/2.promise

Half the leading is called the half-leading. User agents center glyphs vertically in an inline box, which adds half-leading on the top and bottom. For example, if a piece of text is "12pt" high and the line-height value is "14pt", 2pt of extra space should be added: 1pt above and 1pt below the text (this applies to empty boxes as well, as if the empty box contained zero-height text).參考瀏覽器

在深刻垂直居中性以前,咱們先看一個容易引發誤解的示例。(實際上是我本身誤解而已:()app

<div id="container" style="border:solid 1px red;"><span style="background:blue;color:#fff;font-size:20px;line-height:60px;">center glyphs vertically in an inline box.</span></div>

不是說好了會垂直居中嗎?你看字母x明明就在div#container中線的下方呢!
咱們用空格符代替文字就能夠看清楚了。ide

<div style="border:solid 1px red;"><span style="background:blue;color:#fff;font-size:20px;line-height:60px;">&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;</span></div>


「垂直居中」是指字形所在的盒子的垂直中線與line-height所佔據的盒子的垂直中線重合,不是指字形的mean line和line-height所佔據的盒子的垂直中線重合。
L = "line-height" - AD能夠知道行間距可能會負數,那麼垂直居中性還有效嗎?
答案是確定的,L爲負數時,Half-leading天然也是負數,只是上下兩端從增長空間變爲減小等量空間而已。不信你看

<body style="margin:0 10px;padding:0;">
<div style="position:relative;top:100px;font-size:90px;line-height:10px;background:yellow;"><span style="border:solid 1px red;line-height:10px;">x</span></div>
</body>

line-height屬性

'line-height'
Value: normal | <number> | <length> | <percentage> | inherit
Initial: normal
Applies to: all elements
Inherited: yes
Percentages: refer to the font size of the element itself
Media: visual
Computed value: for <length> and <percentage> the absolute value; otherwise as specified

normal

Tells user agents to set the used value to a "reasonable" value based on the font of the element. The value has the same meaning as <number>. We recommend a used value for 'normal' between 1.0 to 1.2. The computed value is 'normal'.

 normal其實就是一個<number>值,不過實際值則由瀏覽器決定,實際值通常在1.0~1.2之間(含兩端)浮動。但實際真的是這樣嗎?

<body style="font-family: Arial, Tahoma, Sans-serif;">
<div style="background:blue;color:#FFF;font-size:10px;">line-height-x-L</div>
<div style="background:blue;color:#FFF;font-size:40px;">line-height-x-L</div>
<div style="background:blue;color:#FFF;font-size:80px;">line-height-x-L</div>
<script type="text/javascript">
var els = document.getElementsByTagName('div')
for (var i = 0, len = els.length; i < len; ++i){
  console.log(els[i].offsetHeight)
}
</script>
</body>

Chrome43的結果

14/10 = 1.4
45/40 = 1.125
92/80 = 1.15
average: 1.225 約爲1.2

Firefox44.0.2

13/10 = 1.3
46/40 = 1.15
92/80 = 1.15
average: 1.2

IE9

11/10 = 1.1
46/40 = 1.15
92/80 = 1.15
average: 1.13333 約爲1.1

經過小數據統計得出normal值的規律:

  1. 不一樣瀏覽器的normal值不相同;

  2. 同一個瀏覽器下,font-size值不一樣,normal值也會有變化;

  3. 同一瀏覽器下,font-size值相同,font-family值不一樣,normal值也會有變化;

  4. normal的平均值確實是在1.0~1.2之間(含兩端),但具體到特定瀏覽器、font-family和font-size時,normal的實際值可能會大於1.2。

<length>

The specified length is used in the calculation of the line box height. Negative values are illegal.

 設置固定值,單位能夠是px、pt。好處是簡單——設置是什麼,line-height的實際高度就是什麼。壞處是子元素默認狀況下會繼承父容器的line-height屬性,若子元素的font-size大於父容器的font-size屬性值,那麼子元素的文本行會十分密集,下降可閱讀性。因此咱們通常採用相對font-size實際大小來設置line-height值的方式,如默認normal方式。

<percentage>

The computed value of the property is this percentage multiplied by the element's computed font size. Negative values are illegal.

 既然採用<length>反作用那麼大,那採用<percentage>這個相對值就萬事大吉了吧!非也,首先咱們要弄清楚<percentage>這個的參考系是啥,另外還要明白子元素的line-height到底繼承的了哪一個值,是<percentage>值仍是父容器實際的line-height值。

  1. <percentage>的參考系的確是font-size;

  2. 子元素繼承的是父容器實際的line-height值。也就是說父容器設置爲font-size:20px;line-height:200%;,那麼子元素繼承來的line-height值爲40px,而不是200%。所以又回到<length>方式的問題上了。

<number>

The used value of the property is this number multiplied by the element's font size. Negative values are illegal. The computed value is the same as the specified value.

 <number>和<percentage>方式同樣,以font-size做爲參考系,以相對值的方式設置line-height。惟一的不一樣就是子元素繼承的是父容器的<number>值,參考系自動變動爲子元素的font-size
 其實line-height:1.2em;line-height:1.2;是等價的。若想將參考系改成根元素的font-size,則須要採用CSS3新增的line-height:1.2rem單位了。
 根據WCAG2.0(萬維網內容可存取性指南)規定「段落中的行距至少要1.5倍」,那麼是否在body那設置一個<number>就一勞永逸呢?請看

<style type="text/css">
body{
  font-size: 16px;
  line-height: 1.5;
}
h1 {font-size:32px;}
p {font-size:16px;}
#footer {font-size:12px;}
</style>
<h1>CSS魔法堂:深刻理解line-height和vertical-align</h1>
<p>In my dual profession as an educator and health care provider, I have worked with numerous children infected with the virus that causes AIDS. The relationships that I have had with these special kids have been gifts in my life. They have taught me so many things, but I have especially learned that great courage can be found in the smallest of packages. Let me tell you about Tyler. </p>
<div id="footer">bed and whispered, 「I might die soon. I’m not scared. When I die, please dress me in red. Mom promised she’s coming to heaven, too. I’ll be playing when she gets there, and I want to make sure she can find me.」</div>


看對於h1標題欄而言,行距太多了。因而得出以下配置:

body{line-height:1.5;}
h1,h2,h3,h4,h5,h6{line-height:1.2;}

vertical-align到底如何對齊呢?

 下面咱們稍微將line-height垂直居中特性中Leading爲負數的示例代碼修改一下,將font-size:90px;line-height:10px;遷移到子元素中.

<div style="position:relative;top:100px;background:yellow;"><span style="border:solid 1px red;font-size:90px;line-height:10px;">x</span></div>

不是說垂直居中嗎?這裏就涉及到一個相對複雜的CSS垂直對齊規則——vertical-align。
注意:前方高能,須要IFC、line box做爲前提知識。(可參考CSS魔法堂:從新認識Box Model、IFC、BFC和Collapsing margins

vertical-algin屬性

'vertical-align'
Value: baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage> | <length> | inherit
Initial: baseline
Applies to: inline-level and 'table-cell' elements
Inherited: no
Percentages: refer to the 'line-height' of the element itself
Media: visual
Computed value: for <percentage> and <length> the absolute length, otherwise as specified

<lenght>:設置相對於baseline的距離,正數表示位於baseline的上方,負數表示位於baseline的下方;
<percentage>:設置以line-height爲參考系,相對於baseline的距離,正數表示位於baseline的上方,負數表示位於baseline的下方;
baseline:默認值。元素的基線與父元素的基線對齊;
top:把元素line box上邊框對齊父元素的line box上邊框;
text-top:把元素line box上邊框對齊父元素的ascent(即content top edge);
super:升高元素的基線到父元素合適的上標位置;
middle:把元素line box中垂點與父元素基線 + x-height/2的高度對齊;
sub:下降元素的基線到父元素合適的下標位置;
text-bottom:把元素line box下邊框對齊父元素的descent(即content bottom edge);
bottom:把元素line box下邊框對齊父元素的line box下邊框;
inherit:繼承父元素的對齊方式。
 怎麼這麼多規則要記啊?我記性很差難道到時還要挨個查嗎?其實概括一下就OK了!

  1. 對齊操做一定涉及操做元素和參考系元素,而vertical-align的值全是指參考系元素的位置,而操做元素則以baseline或linebox上中下做對齊;

  2. 默認對齊方式爲baseline,數量值均是相對於baseline而言。

vertical-align僅對inline-level和table-cell元素有效

注意:vertical-align僅對inline-level和table-cell元素有效,下面示例無效是正常不過的。

<div>
<div style="float:left;font-size:20px;vertical-align:middle;">I'm former</div>
<div style="float:left;font-size:50px;vertical-align:middle;">I'm latter</div>
</div>

IE9+下的vertical-align屬性值詳解(如下內容均在Chrome43中測試)

1.默認對齊方式——baseline

<div style="font-size:14px;">
  <span id="obj" style="font-size:40px;">line-height x vertical-align</span>
  x for reference frame
</div>


這裏x for reference frame做爲參考系,而它的baseline就是span#obj所要對齊的baseline了。
那麼在baseline的基礎上的設置<length>和<percentage>

<div style="font-size:14px;">
  <span id="obj" style="font-size:40px;vertical-align:10px;">line-height x vertical-align</span>
  x for reference frame
</div>
<div style="font-size:14px;">
  <span id="obj" style="font-size:40px;vertical-align:-10px;">line-height x vertical-align</span>
  x for reference frame
</div>
<div style="font-size:14px;line-height:1;">
  <span id="obj" style="font-size:40px;vertical-align:50%;">line-height x vertical-align</span>
  x for reference frame
</div>
<div style="font-size:14px;line-height:1;">
  <span id="obj" style="font-size:40px;vertical-align:-50%;">line-height x vertical-align</span>
  x for reference frame
</div>

2.top——把元素line box上邊框對齊父元素的line box上邊框
 咱們將上面的示例稍微改一下

<span style="font-size:14px;">
  <span id="obj" style="font-size:40px;vertical-align:top;">line-height x vertical-align</span>
  x for reference frame
</span>


確實不一樣了,但這沒法證實是元素的line box上邊框對齊父元素的line box上邊框哦。那麼咱們改改代碼看看

<body style="margin:0 10px;padding:0;">
  <div style="border:solid 1px blue;font-size:14px;line-height:1;">
    <span id="parent" style="background:red;line-height:1;">
      <span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;">line-height x vertical-align</span>
      x for reference frame
    </span>
  </div>
  </body>


經過line-height:1使line box與content box/area的高度一致,雖然span#parentspan#obj的上邊框對齊,但還不能說明什麼。

<body style="margin:0 10px;padding:0;">
  <div style="position:relative;top:100px;;border:solid 1px blue;font-size:14px;line-height:1;">
    <span id="parent" style="background:red;line-height:1;">
      <span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;margin-top:100px;padding-top:100px;background-clip:content-box;">line-height x vertical-align</span>
      x for reference frame
    </span>
  </div>
  </body>


沒有任何變化。那改變line-height又如何呢?

<body style="margin:0 10px;padding:0;">
  <div style="border:solid 1px blue;font-size:14px;line-height:1;">
    <span id="parent" style="background:red;line-height:2;">
      <span style="display:inline-block;vertical-align:top;background:green;">
      <span id="obj" style="background:yellow;font-size:40px;line-height:2;">line-height x vertical-align</span>
      </span>
      x for reference frame
    </span>
  </div>
  </body>


爲了讓span#obj的Half-leading清晰可見,特地添加一個display:inline-block的inline box包裹着span#obj。而span#parent也增大了Half-leading的高度。如今能夠咱們清晰看到確實是span#obj的line box的上邊框對齊父元素的line box上邊框。(同理證實了vertical-align:bottom是把元素line box下邊框對齊父元素的line box下邊框;)
注意:chrome下若外層div不添加font-size:14px;line-height:1;屬性,將致使span#parent上有條空白間隙

緣由十分簡單,那是由於span#parent的對齊方式是baseline,參考系是div的baseline,而div的line-height爲normal,有空白間隙就是固然的事了。經過JS就能夠看清楚了。

var div = document.getElementsByTagName('div')[0]
console.log(div.childNodes[0].nodeType) // 顯示3,就是TextNode

其實除了在div上設置line-height:1以外,咱們還能夠在span#parent上設置vertical-align:top來解決。

<body style="margin:0 10px;padding:0;">
  <div style="border:solid 1px blue;font-size:14px;">
    <span id="parent" style="background:red;line-height:1;vertical-align:top;">
      <span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;">line-height x vertical-align</span>
      x for reference frame
    </span>
  </div>
  </body>


3.text-top——把元素的line box上邊框對齊父元素的ascent(即content top edge)

<body style="margin:0 10px;padding:0;">
  <div style="position:relative;top:100px;border:solid 1px blue;font-size:14px;line-height:1;"> <span id="parent" style="background:red;line-height:2;">
      <span id="obj" style="background:yellow;vertical-align:text-top;font-size:2px;line-height:1;">*</span>
      x for reference frame
    </span>
  </div>
  </body>

<body style="margin:0 10px;padding:0;">
  <div style="position:relative;top:100px;border:solid 1px blue;font-size:14px;line-height:1;"> <span id="parent" style="background:red;line-height:2;">
      <span style="display:inline-block;vertical-align:text-top;border-top:solid 2px green;">
      <span id="obj" style="background:yellow;font-size:2px;line-height:2;">*******</span>
      </span>
      x for reference frame
    </span>
  </div>
  </body>


4.middle——把元素line box中垂點與父元素基線 + x-height/2的高度對齊

<body style="margin:0 10px;padding:0;">
  <div style="border:solid 1px blue;font-size:40px;line-height:1;"> 
    <span id="parent" style="background:red;line-height:1;">
      <span id="obj" style="padding-top:10px;display:inline-block;background:yellow;font-size:15px;line-height:1;vertical-align:middle;">*******</span>x for reference frame
    </span>
  </div>
  </body>


注意
當元素的display:inline-block/inline-table等對應的是atomic inline-level box時,其line box高度爲margin box的高度。若元素對應的是inline box,則其最小高度爲line-height,最大則由子盒子決定。

IE5.5~8下vertical-align屬性值詳解

 因爲我工做中沒有適配IE8等歷史瀏覽器的需求,所以詳細內容請參考@張鑫旭的CSS vertical-align的深刻理解(二)之text-top篇
 簡單來講IE5.5~IE8下vertical-align:text-top是把元素的ascent對齊父元素的ascent(即content top edge)

真的掌握vertical-align了嗎?

 到這裏理論部分已經介紹完了,是時候經過示例來驗證本身了!

單行文字的垂直居中對齊

<style type="text/css">
      .slma1{
        border:solid 3px #888; 

    font-size: 14px;
    line-height: 100px;
      }
    </style>
    <p class="slma1">
        字體大小14px
    </p>


    <style type="text/css">
      .slma2{
        border:solid 3px #888; 

    font-size: 14px;
    line-height: 100px;
      }
      .slma2 i{font-style:normal;font-weight:bolder;vertical-align:middle;}
      .slma2 span{font-size:30px;vertical-align:middle;}
    </style>
    <p class="slma2">
      <i>* </i>字體大小爲14px<span>字體大小爲30px</span>
    </p>

行數不固定的多行文字的垂直居中對齊

<style type="text/css">
  .mlma1{
    border:solid 3px #888; 

    font-size: 14px;
    line-height: 100px;
  }
  .mlma1 span{
    line-height: 1.5;
    display: inline-block;
    vertical-align: middle;
  }
</style>
<p class="mlma1">
  <span> 第一行文本<br/>the second one.</span>&nbsp;
</p>

大小不固定的圖片的垂直居中對齊

<style type="text/css">
      .a{width: 100px; height: 100px;}
      .b{width: 80px; height: 80px;}
      .c{width: 60px; height: 60px;}
      .container{
    background: #ccc;
    
    line-height: 200px;
      }
      img{padding:5px;border:solid 1px blue;vertical-align:middle;}
    </style>
    <div class="container">
        <img class="a" src="./john.png"/>
        <img class="b" src="./john.png"/>
        <img class="c" src="./john.png"/>
        <img class="b" src="./john.png"/>
    </div>

總結

尊重原創,轉載請註明來自:http://www.cnblogs.com/fsjohnhuang/p/5307706.html^_^肥子John

感謝

深刻了解css的行高Line Height屬性
我對CSS vertical-align的一些理解與認識(一)
CSS vertical-align的深刻理解(二)之text-top篇
CSS深刻理解vertical-align和line-height的基友關係
css行高line-height的一些深刻理解及應用
大小不固定的圖片、多行文字的水平垂直居中
深刻理解 CSS 中的行高與基線

相關文章
相關標籤/搜索