你所不知道的vertical-align

有些東西我們經(jīng)常用,但是我們卻并不了解它的原理,所以一旦換了場景,好多東西就不知道該怎么用了。最近一直很糾結(jié)vertical-align到底是怎么回事,因?yàn)椴还苁谴怪睂R元素,還是消除inline-block的縫隙也好,我們總能用到它,可是就是不知道為什么。抱著刨根問底的態(tài)度,今天在網(wǎng)上發(fā)現(xiàn)了一篇好文章,無奈是英文,博主不是什么英語大神,看到英語也頭疼,但奈何好文章都是英文。那就來吧,翻譯一下午,雖然是撕心裂肺,但是感覺受益匪淺,文中有翻譯不當(dāng)?shù)牡胤竭€請各位看官多多指正。

小二,上原文鏈接:Vertical-Align: All You Need To Know


我們經(jīng)常需要在豎直方向上對齊一些并肩排列的元素。
CSS為我們提供了一些實(shí)現(xiàn)方法。有時(shí)候我會(huì)使用float,有時(shí)候也用position:absolute,有時(shí)候甚至利用手動(dòng)添加內(nèi)外邊距的方法。
我并不喜歡這些方法。浮動(dòng)只能對齊它們的頂部,而且需要手動(dòng)清除浮動(dòng)。絕對定位會(huì)使元素脫離文檔流,以致于它們就不能影響周圍的元素了。再說說使用固定的內(nèi)外邊距,會(huì)突然導(dǎo)致微弱的改變。
這里還有另一種值得信任的方法,那就是vertical-align。從專業(yè)角度講,使用vertical-align來進(jìn)行布局是一種“黑科技”,因?yàn)榘l(fā)明它并不是出于這個(gè)目的。vertical-align是為了對齊文本和緊鄰文本的元素。盡管如此,你也能在不同場景下使用vertical-align去進(jìn)行靈活細(xì)微的元素對齊工作,而且你并不需要知道元素的具體尺寸。

Vertial-Align的“詭異”

但是,vertical-align有時(shí)候真的讓人抓狂。它似乎有一些不可告人的秘密。例如,有時(shí)候你對一些元素設(shè)置vertical-align,你會(huì)發(fā)現(xiàn)它的對齊方式并沒有改變,但是同一行的其它元素卻變了。我時(shí)常哭暈在vertical-align的廁所中。
不幸的是,大部分關(guān)于它的資料都是淺顯的。尤其是,如果你想找vertical-align關(guān)于布局方面的介紹時(shí),他們大多告訴你錯(cuò)誤的信息——vertical-align可以控制元素內(nèi)部所有元素的豎直排列。他們總是給出最基礎(chǔ)的場景應(yīng)用,卻從不介紹復(fù)雜的情況。
所以我給自己立下任務(wù),要一次弄清所有關(guān)于vertical-align的知識。我看完W3C的CSS說明然后自己動(dòng)手做了一些實(shí)驗(yàn)。結(jié)果就是這篇文章了。
那么,然我們一起來了解游戲規(guī)則吧。

使用vertical-align的前提條件

vertical-align用于對齊行內(nèi)級元素。行內(nèi)級元素的display屬性是如下值中的一種:

  • inline
  • inline-block
  • inline-table(本文不涉及,有興趣自己看)

inline元素是包裹文本的基本標(biāo)簽。
inline-block元素顧名思義是存在于inline中的block元素。它們可以設(shè)置寬高、內(nèi)外邊距、和邊框。

inline級元素是一個(gè)挨著一個(gè)排在一行的元素。一旦一行放不下所有元素的時(shí)候,就會(huì)在下面創(chuàng)建一個(gè)新行。所有的行都有一個(gè)叫做line-box的東西,它是用來包裹這一行所有內(nèi)容用的。line-box的高度是根據(jù)一行內(nèi)所有內(nèi)容的高度定的。如下圖中所示:line-box的上下邊沿用紅線標(biāo)出。(line-box的邊沿平時(shí)是看不到的,畫出來是為了方便讀者理解)

Paste_Image.png

line-box規(guī)定出了我們對齊元素時(shí)的活動(dòng)范圍。在line-box中vertical-align負(fù)責(zé)每個(gè)元素的豎直對齊方式。那么問題就來了,什么是元素的對齊呢?

關(guān)于base-line(基線)和outer edge(外邊沿)

理解垂直對齊最關(guān)鍵的一點(diǎn)在于理解相關(guān)元素的基線。還有一些場景中,元素的上下邊沿也至關(guān)重要。現(xiàn)在就讓我們看一下不同元素的基線和上下邊沿到底在哪里?

inline元素

Paste_Image.png

從上圖中你可你可以看到三種情況。行高的上下邊沿用紅線表示,綠線表示字體的高度,藍(lán)線表示基線。左圖中的行高和字體尺寸相同,所以紅線和綠線重合在一起了。中間的圖片,行高是字體高度的兩倍。右圖行高是字體高度的一半。
行內(nèi)元素的外邊沿就是它們的行高的上下邊沿。即使行高比字體高度小也沒有關(guān)系。因此,行內(nèi)元素的外邊沿就是上圖中的紅線。

行內(nèi)元素的基線是字符下面的一條線。具體是圖中的藍(lán)線。大約的說,基線是字體正中線下面的一條線。想具體了解的請看W3C的詳細(xì)說明

inline-block元素

Paste_Image.png

從左到右依次是:一個(gè)包含in-flow內(nèi)容(一個(gè)字母C)的inline-block元素;一個(gè)包含in-flow內(nèi)容并且設(shè)置了over-flow:hidden屬性的inline-block元素;一個(gè)沒有in-flow內(nèi)容(但是設(shè)置了高度屬性)的inline-block元素。三個(gè)例子都設(shè)置了margin屬性,紅線是margin的邊緣,黃色部分是邊框,綠色部分是內(nèi)邊距padding,藍(lán)色部分是內(nèi)容。藍(lán)線是各個(gè)元素的基線。
inline-block元素的外邊沿是它們的margin-box的上下邊沿。也就是圖中的紅線。
inline-block元素的基線取決于元素是否有in-flow內(nèi)容:

  • 包含in-flow內(nèi)容的inline-block元素的基線是普通文檔流中最后一個(gè)元素內(nèi)容的基線(例如左圖)。這最后一個(gè)元素的基線如何定位,那就看它是什么類型的元素了。
  • 包含in-flow內(nèi)容而且設(shè)置了overflow屬性(值非visible)的inline-block元素,其基線是margin-box的下邊沿(例如中間的圖)。所以它的基線就和自己的底邊沿重合了。
  • 不包含in-flow內(nèi)容的inline-block元素和上者相同,同樣是底邊線。

什么是line box?

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3068436-7140e215c7d96836.png?
imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我為line-box中的text-box(下面會(huì)講到)加上了上下邊沿(綠線)以及基線(藍(lán)線)。我也為文字元素加上了背景色(灰色)。
line-box有一個(gè)上邊沿,它和行內(nèi)最高的元素的上邊沿對齊;同樣也有一個(gè)下邊沿和行內(nèi)最低元素的下邊沿對齊。這兩個(gè)邊沿也就是圖中的紅線。

line-box的基線是會(huì)變化的

"CSS 2.1 does not define the position of the line box's baseline."
——the W3C Specs

這可能是最令人困惑的部分。這就意味著,line-box的基線是會(huì)根據(jù)一定的規(guī)則動(dòng)態(tài)改變的。
由于line-box的基線是不可見的,所以你也不可能準(zhǔn)確的說出它到底在哪里。但是能通過一個(gè)簡單方法知道它在哪。只要在一行內(nèi)容的行首添加一個(gè)字符就行,例如:我加了一個(gè)"x"(行首灰色的那個(gè))。如果這個(gè)字符沒有進(jìn)行任何人為方式的對齊,那么它的基線就默認(rèn)是在line-box的基線上。
line-box的基線周圍的空間,我們可以稱之為text box。你可以把text box看做是一個(gè)在line-box中沒有進(jìn)行任何對齊的inline元素。它的高度等于父元素的字體大小。因此text box是用于包裹line box中沒有設(shè)置任何對齊的文字的。圖中綠線之間的部分就是text box。由于text box是和基線緊密相連的,因此它會(huì)隨著基線的移動(dòng)而移動(dòng)。(在W3C說明中,text box叫做strut)
現(xiàn)在我們知道了所有的預(yù)備知識點(diǎn),讓我們做一下總結(jié):

  • 有一個(gè)叫做line-box的區(qū)域。各個(gè)元素是要在這里進(jìn)行垂直對齊的。它包含一條基線,一個(gè)text box,一個(gè)上邊沿,一個(gè)下邊沿。
  • 這里還有一些inline級別的元素。這些都是我們要進(jìn)行對齊的對象。它們同樣有自己的基線,一個(gè)上邊沿,一個(gè)下邊沿。

Vertical Align都能使用哪些值

我們通過使用vertical-align可以把上面我們介紹的那些參考點(diǎn)(基線,上線邊沿等)設(shè)置成確定的關(guān)系。
主要分一下兩種情況:

將元素的基線相對于line-box的基線進(jìn)行對齊

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3068436-e22cccdbf8b09e87.png?
imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  • baseline:將元素的基線對齊到line-box的基線上;
  • sub:將元素的基線對齊到line-box基線下方;
  • super :將元素的基線對齊到line-box的基線上方;
  • <percentage> :元素的基線相對于line-box的基線進(jìn)行確定距離的對齊,定位的距離和方向由設(shè)置的百分比數(shù)值決定,百分比是相對于line-height的。
  • <length>:元素的基線相對于line-box的基線進(jìn)行確定距離的對齊,定位的距離和方向由設(shè)置的具體長度值決定。

將元素的外邊沿相對于line-box的基線進(jìn)行對齊

Paste_Image.png
  • middle:使元素的上沿和下沿的中點(diǎn)對齊到字母“x”的基線上邊加上一半x的高度上(其實(shí)就是字母x的正中間)。

將元素的外邊沿相對于line-box的text box對齊

Paste_Image.png

以下的兩種情況,其實(shí)也是相對于line-box的基線的一種對齊,因?yàn)閠ext-box的上下邊沿也是取決于基線的。

  • text-top:元素的上邊沿對齊到line-box的text-box的上邊沿;
  • text-bottom:元素的下邊沿對齊到line-box的text-box的下邊沿。

將元素的外邊沿相對于line-box的外邊沿對齊

Paste_Image.png
  • top:將元素的上邊沿和line-box的上邊沿對齊;
  • bottom:將元素的下邊沿和line-box的下邊沿對齊;

為什么Vertical-Align會(huì)表現(xiàn)出這樣的作用呢?

我們現(xiàn)在能夠在具體的場景下更細(xì)致的研究vertical-align了。尤其是,我們將解決一些常見的問題。

使圖標(biāo)和文字居中

長久以來一直困擾我的一個(gè)問題:我想讓一個(gè)圖標(biāo)和它旁邊的文字居中對齊時(shí),僅僅對圖標(biāo)使用vertical-align:middle似乎并沒有真正的使兩者居中對齊。
來看看下面這個(gè)例子:

Paste_Image.png

<!-- left mark-up -->
<span class="icon middle"></span>
Centered?
<!-- right mark-up -->
<span class="icon middle"></span>
<span class="middle">Centered!</span>

<style type="text/css"> 
.icon { display: inline-block; /* size, color, etc. */ } 
.middle { vertical-align: middle; }
</style>

下圖還是這個(gè)例子,不過我為其添加了一些標(biāo)注幫助理解,這些線都是我們之前已經(jīng)講過的:

Paste_Image.png

這樣看是不是就有些明白是怎么回事了。因?yàn)樽髨D中的文字沒有經(jīng)過對齊處理多以它默認(rèn)是在text-box中的,它的基線和line-box的基線是重合的。通過給灰色方塊設(shè)置vertical-align: middle;,我們的確把灰色方塊的正中心對準(zhǔn)了x字母的正中心,但是x字母的正中心并不是其所在的text-box的正中心,而是text-box中心稍稍的偏下了一點(diǎn)。
再看右圖,我們把“center”包裹起來并為也設(shè)置vertical-align: middle;,“center”的基線就不再和line-box的基線重合了,而是稍稍下移了。結(jié)果圖標(biāo)和右邊的文字就完美的居中對齊了。

line-box的基線是會(huì)移動(dòng)的

使用vertial-align是的一大缺陷就是:line-box的基線的位置受其內(nèi)部所有元素的影響。我們假設(shè)這樣一種情況,一個(gè)元素相對于line-box的基線對齊,那么當(dāng)line-box的基線位置發(fā)生改變時(shí),那么元素的位置也會(huì)跟著改變。

來看一些例子:

  • 如果有一個(gè)比較高的元素剛好撐滿了line-box,vertical-align對它來說就沒用任何影響了。因?yàn)樗南旅婧蜕厦嬉呀?jīng)沒有位置可以讓它再移動(dòng)了。下面兩幅圖中矮小的盒子都設(shè)置vertical-align:baseline。左圖的高盒子設(shè)置為vertical-align:text-bottom。右圖的高盒子設(shè)置為vertical-align:text-top。你就會(huì)發(fā)現(xiàn)兩幅圖中l(wèi)ine-box的基線是不再同一位置的,因?yàn)榘凶邮歉€對齊的。
    Paste_Image.png
<!-- left mark-up -->
<span class="tall-box text-bottom"></span>
<span class="short-box"></span>
<!-- right mark-up -->
<span class="tall-box text-top"></span>
<span class="short-box"></span>
<style type="text/css"> 
.tall-box, .short-box { display: inline-block;
/* size, color, etc. */ }
 .text-bottom { vertical-align: text-bottom; } 
.text-top { vertical-align: text-top; }
</style>

當(dāng)我們?yōu)檫@個(gè)比較高的元素設(shè)置其它的vertical-align值時(shí),也會(huì)有相同的表現(xiàn)。

  • 即使設(shè)置vertical-align的值為bottom(左圖)和top(右圖)也會(huì)移動(dòng)基線的位置。
    Paste_Image.png
<!-- left mark-up -->
<span class="tall-box bottom"></span>
<span class="short-box"></span>
<!-- right mark-up -->
<span class="tall-box top"></span>
<span class="short-box"></span>
<style type="text/css"> 
.tall-box, .short-box { display: inline-block; /* size, color, etc. */ } 
.bottom { vertical-align: bottom; }
.top { vertical-align: top; }</style>
  • 將兩個(gè)比較高的盒子放置在一行,調(diào)整它們兩個(gè)的垂直對齊方式使基線能夠同時(shí)滿足兩種對齊。然后line-box的的高度就得到了調(diào)整(如左圖)。再添加第三個(gè)元素,它的高度不會(huì)超過line-box的邊緣,因?yàn)樗亩ㄎ环绞郊炔粫?huì)影響line-box的高度,也不會(huì)影響基線的位置(如中圖)。如果它真的超出了原有l(wèi)ine-box的邊緣,line-box的高度和基線都會(huì)重新調(diào)整。這種情況我們的前兩個(gè)盒子就會(huì)下移(如右圖)。


    Paste_Image.png
<!-- left mark-up -->
<span class="tall-box text-bottom"></span>
<span class="tall-box text-top"></span>
<!-- mark-up in the middle -->
<span class="tall-box text-bottom"></span>
<span class="tall-box text-top"></span>
<span class="tall-box middle"></span>
<!-- right mark-up -->
<span class="tall-box text-bottom"></span>
<span class="tall-box text-top"></span>
<span class="tall-box text-100up"></span>
<style type="text/css">
.tall-box { display: inline-block; /* size, color, etc. */ } 
.middle { vertical-align: middle; }
 .text-top { vertical-align: text-top; }
 .text-bottom { vertical-align: text-bottom; } 
.text-100up { vertical-align: 100%; }
</style>

inline級的元素下面為什么會(huì)有一個(gè)小空隙

看看下面的例子。通常都會(huì)有如下情況出現(xiàn),當(dāng)你想對齊豎直對齊li元素的時(shí)候。


Paste_Image.png
<ul> 
<li class="box"></li>
<li class="box"></li> 
<li class="box"></li>
</ul>

<style type="text/css">
 .box { display: inline-block; /* size, color, etc. */ }
</style>

正如你所看到的,li元素其實(shí)默認(rèn)是和基線對齊的,基線下面是留有一部分空白的,這個(gè)空白是可以容納半個(gè)“x”的空間。這就導(dǎo)致了空隙的存在。如何解決?我們可以改變基線的位置,例如給li元素設(shè)置對齊方式為vertical-align: middle

Paste_Image.png
<ul> 
<li class="box middle"></li>
<li class="box middle"></li> 
<li class="box middle"></li>
</ul>
<style type="text/css"> 
.box { display: inline-block; /* size, color, etc. */ } 
.middle { vertical-align: middle; }
</style>

這種情況不會(huì)發(fā)生在包含文本內(nèi)容的inline-block元素身上,因?yàn)?strong>文本內(nèi)容已經(jīng)把基線的位置抬高了。

inline級元素之間的縫隙會(huì)打斷布局

這個(gè)問題主要還是inline級元素自身問題造成的。但是鑒于這種情況也影響了豎直對齊,我們還是了解一下比較好。

和上個(gè)例子一樣,這個(gè)例子也是由空隙造成的。這個(gè)空隙主要來自于inline元素之間的空格符。inline元素之間的所有空格符會(huì)合并為一個(gè)空格。如果你想讓兩個(gè)inline元素并排顯示,并且width:50%,那么這個(gè)空格就是個(gè)絆腳石。一行的空間不足以容納兩個(gè)width:50%和一個(gè)空格。所以右邊的元素就被擠下去了。要想消除縫隙,你就得消除空格。

Paste_Image.png

<!-- left mark-up -->
<div class="half">50% wide</div>
<div class="half">50% wide... and in next line</div>
<!-- right mark-up --> 
<div class="half">50% wide</div><!--
--><div class="half">50% wide</div>

<style type="text/css"> 
.half { display: inline-block; width: 50%; }
</style>

Vertical-Align解密

就是這樣。一旦你知道了規(guī)則之后它看起來就不那么復(fù)雜了。如果下次vertical-align再不聽話了,就問如下的兩個(gè)問題:

  • line-box的基線,上下邊沿在哪里?
  • inline級元素的基線,上下邊沿在哪里?

我相信問題馬上就會(huì)得到解答。


至此結(jié)束,不知道有幾個(gè)人能耐心的看完……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內(nèi)容