在 css 中實現垂直居中不少時候會用到 vertical-align ,不過我一直對 vertical-align 的使用糊里糊塗,如今整理一下關於它的一些知識點。原文連接css
vertical-align屬性只能適用於內聯元素( inline )、內聯塊元素( inline-block )和table-cell元素( td ),包括 display 屬性爲 inline 、inline-block 和 table-cell 的元素。因爲元素在浮動和絕對定位以後會自動轉換爲塊元素( block ),因此浮動和絕對定位元素也沒有 vertical-align 屬性。html
關於文本的頂線、中線、基線和底線已經在介紹行高的文章中的配圖中解釋過了。安全
line box 的基線等於這一行中沒有通過任何人爲對齊設置的文本的基線。less
inline block 元素的基線位置,在css中規定是:測試
The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.字體
inline-block 元素的基線是這個元素下正常文檔流中最後一個 line box 的基線,除非這個元素中沒有正常流的 line box 或者自己的 overflow 屬性值不是默認的 visible ,這個時候 inline-block 元素的基線位置是margin的底邊緣。.net
如下是 w3c 中關於vertical-align取值的規定:code
baseline: 默認值,盒子的基線與父級盒的基線對齊。若是這個盒子沒有基線,就讓這個盒子的 margin 底邊緣和父級盒基線對齊。orm
middle: 將盒子的垂直中心點與父級盒子基線往上 X 一半高度的位置對齊。htm
sub: 下降盒子的基線到父級盒合適的下標位置。
super: 提升盒子的基線到父級盒合適的上標位置。
text-top: 將盒子的頂部(top)與父級盒子內容區域的頂部對齊。
text-bottom: 將盒子的底部(bottom)與父級盒子內容區域的底部對齊。
%: 將盒子相對基線位置上移或下移多少位置(百分比的值時相對於行高 line-height )," 0% "時位置與設置 baseline 一致。
數值: 將盒子相對基線位置上移或下移多少位置。0px 時位置與設置 baseline 一致。
top: 將盒子的頂部與行框 line box 的頂端對齊(行框的頂部就是這一行行內框的最高點)。
bottom: 將盒子的底端與 行框 line box 的底端對齊(行框的底端就是這一行行內框的最低點)。
以上前8個的取值是相對於盒子的父級盒子,後2個取值是相對於這一行的行框 line box 。從以前行高的文章咱們知道了盒子的頂部與父級盒子內容區頂部的間距就是半行距,當盒子的字體大小等於 line-height 大小時,盒子和父級盒子的內容區域會重疊,也就是下面 demo 中 表示 text-top 和 text-bottom 的線會與表示 top 和 bottom 的線重合。
下面 demo 來自 Vertical-Align: All You Need To Know。便於理解各類取值之間的關係。
verrical-align 參考線模型
上面 demo 中,不一樣顏色的高度爲 0 的線設置不一樣的 vertical-align 值,利用 margin-right 負值將全部的線和最後一個行塊放置在同一個行框 line box 中。
剛開始看到這個 demo 的時候,徹底不清楚爲何這幾個寬度和父級同樣線可以放在同一個行框中,瞭解以後知道是 margin 負值的做用, margin 負值的相關知識在文章最後。
demo 中的全部元素都處在同一個行框 line box 中,這幾根線表示這個行框的各個參考線。六個灰塊分別設置不一樣的 vertical-align 值來與父元素對齊。仔細觀察
基線對齊是子元素的基線和父元素的基線對齊,demo 中這個子元素的基線是末尾的X的下邊緣。
仔細測量居中對齊塊的上下距離以後咱們會發現,這個塊並非徹底得居中對齊。這並非 bug ,而是安全按照 w3c 的規定:「盒子的垂直中心點與父級盒子基線往上 X 一半高度位置對齊」, middle 參考線也穿過最左邊 X 的中心,而字符具備下沉特性,因此 X 的中心並非字符所在行內框的中心點,也就不在整個行框的中心點。咱們能夠將 font-size 設爲 0 來讓元素徹底垂直居中。
對齊小圖標
因爲 vertical-align 爲 middle 並不能讓元素徹底居中,會受到字體大小的干擾,在這種小圖標的對齊上使用 middle 會使得這種干擾更明顯,因此設置像素值讓小圖標相對於基線偏移的作法更準確一些。
查看 demo(測試發現預覽中的按鈕點擊無效,請直接點擊原連接測試)
上面 demo 中,當咱們改變圖片的 vertical-align 屬性值時,發現整個行框的基線位置也發生了變化。這是由於這個行框中最高點和最低點都在圖片上,因此行框的高度就等於這個圖片的高度,當圖片的 vertical-align 值發生變化時,行框內沒有足夠的空間可讓圖片移動,因此只能移動基線。
並且當圖片的 vertical-align 值設置爲 middle 時,圖片並無在父級中垂直居中,這是由於圖片只是在所在行框中近似垂直居中,要想讓圖片在父級中居中,可讓行框的高度等於父級盒子的高度。也就是可讓父級的 line-height 等於高度。
圖片垂直居中
字體大小設置爲 0 是讓元素徹底垂直居中
在上面的例子中,有沒有文本標籤都沒有區別,咱們能夠看作父級盒子中有一個空白的文本節點來做爲基線位置的參考。
方法2連接描述
上面 demo 的方法建立一個高度爲 100% 的僞元素(空元素也能夠),這樣這個元素的基線就會和父級的基線重合,空元素的垂直中心點也與父級的中心重合,圖片也會垂直居中。
文本垂直居中
垂直居中文本的方法和圖片的方法差很少,文本標籤 inline-block 化,而後按照居中圖片的方法來居中。其中須要注意的是父級元素設置 font-size 爲 0 ,這是爲了消除僞元素(或者空元素)與文本標籤之間的間隙,若是這個間隙存在,那麼這個僞元素會換行,不和文本元素在同一個行框中,垂直居中就會失效。
margin 的四個取值中,本質上雖然都是在和其餘元素之間產生間距,但實現的方法卻不同。其中 left 和 top 值是相對相鄰元素的邊界改變本身的位置,而 right 和 bottom 是相對元素自己位置來影響周邊元素的位置(其實是影響右邊和下邊相鄰元素的參考線)。
當 margin 值爲正值時,會按照正常邏輯向元素四周產生間距。當元素的 margin-left 和 margin-top 爲負值時,元素會向左或向上移動,當元素的 margin-right 和 margin-bottom 爲負值時,元素右邊和下邊的元素的參考線位置會變化。
上面的 demo 中,六條參考線的寬度都與父元素一致,因此默認會處在六個不一樣的行框 line box 中。但給他們都設置了 margin-right 負值,這個負值足夠小的話,會將下一行的元素拉上來。
正常狀況下 margin-right 的值等於負的元素寬度就能夠實現,不過六個 inline-block 元素之間默認會有間隙,咱們能夠把代碼寫成一行來避免這個間隙的出現,不過可讀性就比較差,這個間隙的大小默認是和父元素的字體大小有關的,也能夠把父元素 font-size 設爲 0 來消除間隙,不過這樣就會致使幾根參考線重合,影響表達效果。因此上面 demo 中線元素的 margin-right 值的絕對值都稍大於元素的寬度,這是爲了抵消正常流中 inline-block 元素之間的間隙。