關於 vertical-align 你應該知道的一切

這是第 41 篇不摻水的原創,想獲取更多原創好文,請掃 👆上方二維碼關注咱們吧~
本文首發於政採雲前端團隊博客:關於 vertical-align 你應該知道的一切css

前言

vertical-align,寫過 CSS 的朋友們確定都知道這個屬性的做用,顧名思義,垂直對齊,主要目的用於將相鄰的文本與元素對齊。MDN 中對它的定義以下:html

一種簡單的 CSS 屬性,用來指定行內元素(inline)或表格單元格(table-cell)元素的垂直對齊方式。前端

咱們對於它的直觀定義是與 text-align:center 相相似,一個控制水平方向對齊方式,一個控制垂直方向對齊方式。可是在不少狀況下,咱們發現設置屬性以後並沒生效。接下來讓咱們步步深刻學習,共同揭開 vertical-align 的神祕 」面紗「 吧。segmentfault

首先咱們先講一下,要實現垂直居中,咱們爲何選擇 vertical-align 這樣一個不起眼的 CSS 屬性。瀏覽器

  • float:只能對齊它們的頂部,並且可能致使佈局塌陷,須要手動清除
  • position:absolute:會使元素脫離文檔流,以至於它們不能影響周圍的元素
  • 手動添加內外邊距的方法:須要父元素高度固定
  • transform:translateY:屬於 CSS3 新特性,對 IE八、IE9 有一些兼容性的問題

使用 vertical-align 你能在不一樣場景下去進行靈活細微的元素對齊工做,而且它有很好的的兼容性,詳情以下圖所示:wordpress

前置準備

在認識 vertical-align 屬性以前,首先要了解幾個基本的概念。佈局

  • 基線:書寫英語字母時,字母 X 底部所在的位置,能夠了解下 字母’x’在CSS世界中的角色和故事post

  • 行高( line-height ):兩行文字基線之間的距離性能

  • 內聯盒子,更深刻的理解能夠參考 CSS盒子模型學習

  • content area : 圍繞文字看不見的 Box,其大小與 font-size 有關

  • inline boxes: 不會成塊顯示,而是並排顯示在一行的 boxes ,如 span,a,em等標籤以及匿名 inline boxes(即不含把標籤的裸露的文字)

  • line boxes: 由一個一個的 inline boxes 組成,一行即爲一個 line box

  • containing box: 外層盒子模型,包含了其餘的 boxes

  • 起做用的前提:元素爲 inline 水平元素或 table-cell 元素,包括 span , img , input , button , td 以及經過 display 改變了顯示水平爲 inline 水平或者 table-cell 的元素。這也意味着,默認狀況下, div , p 等元素設置 vertical-align 無效

值得注意的是:例如 float 和 position: absolute ,一旦設置了這兩個屬性之一,元素的 display 值被忽略,強制當成 block 方式處理,所以,vertical-align 也就失去了做用。

vertical-align 屬性值

除 Inherit 繼承 以外,vertical-align 的屬性值能夠歸爲如下4類

  • 線類,如 Baseline、Top、Middle、Bottom ;
  • baseline 爲 vertical-align 的默認值,其意思是指基線對齊

咱們能夠把每個行框盒子的後面想象有一個看不見的節點 x(該節點繼承了 line-height ),由於默認對齊方式爲基線對齊,因此.text 就是和這個字母 x 的下邊緣對齊。

在實際應用中咱們常常會遇到下圖這種狀況,你可能會容易的解決這種沒法對齊的問題,可是你知道是什麼緣由致使他們這個樣子嗎?

<ul class="box">
  <li>文本</li>  
  <li></li>
</ul>
<style> .li { font-size: 20px; width: 160px; height: 160px; display: inline-block; border: 1px solid #ccc; } </style>
複製代碼

這裏就涉及到了 inline-block 基線的定義,inline-block 的基線是正常流中最後一個(行盒子) line box 的基線,可是,若是這個 line box 裏面沒有 inline boxes 或者其 overflow 屬性值不是 visible,那麼其基線就是 margin bottom 的邊緣。

如上圖所示,第一個元素基線是子元素」文本「的基線,而第二個是盒子的底邊緣,默認基線對齊,兩個元素基線位置不一致,全部會產生上圖現象,知道了緣由,咱們只需設置元素的 vertical-align 屬性爲 top/bottom/middle 就能夠輕鬆對齊了。

  • top 與 bottom

對於內聯元素,指的是元素的頂部(底部)和當前行框盒子的頂部(底部)對齊;即與 line-box 的頂部(底部)對齊 對於 table-cell 元素,指的是元素的頂 padding 邊緣和表格行的頂部對齊。

基本效果以下圖:

  • middle 這個屬性值用得比較多。

對於內聯元素指的是元素的垂直中心點與行框盒子基線往上 1/2x-height 處對齊,簡單點說就是字母 X 的中心位置對齊;對於 table-cell 元素,指的是單元格填充盒子相對於外面的表格行居中對齊。

  • 文本類

text-top,指的是盒子的頂部和父級內容區域的頂部對齊,即與 content-area 頂部對齊。 text-bottom,指的是盒子的底部和父級內容區域的底部對齊,即與 content-area 底部部對齊。

例子以下:

<div class="box">
    <span class="f12">12px</span>
    <span class="f16">16px</span>
    <span class="f20">20px</span>
    <img src="./panda.jpg"/>
</div>
<style> .box { font-size: 16px; } img { vertical-align: text-top; width: 100px; height: 100px; } .f12 { font-size: 12px; } .f16 { font-size: 16px; } .f20 { font-size: 20px; } </style>
複製代碼
  • content-area 即圍繞文字看不見的 box,其大小與 font-size 有關,能夠當作是鼠標選中文字後高亮的背景色區域,上面的例子中,因爲父元素字體設置的是 16px ,因此圖片的 vertical-align 設置 text-top 的時候,就能夠當作是跟子元素爲 16px 元素的內容區域頂部對齊,它與 line-height 無關
  • 上標下標類

如 sub、super;這兩個屬性用的比較少。

  • super 屬性效果至關於 html 標籤 <sup></sup> 的效果
  • sub 屬性效果 至關於 html 標籤 <sub></sub> 的效果
  • 數值百分比類,如 10px、1em、5%

之因此數值和百分比寫在一塊兒主要是他們有如下共性:都帶數字、都支持負值、行爲表現一致

  • vertical-align 支持數值的特性,兼容性也很是好,但大部分開發人員殊不知道 vertical-align 支持數值。對於數值,咱們要知道的是:一、正值表示由基線往上偏移,負值表示由基線往下偏移。二、百分比則是基於 line-height 來計算的

須要注意的是:除了 top 與 bottom 是使元素相對於整行垂直對齊外,其餘屬性值都是相對於父元素。因此,在開發時,咱們只須要關注當前元素和父級,兩元素先後並無直接影響

vertical-align 與 line-height 之間的基友關係

說到 vertical-align 就要講到它與 line-height 之間密切的關係,從上面咱們都知道百分比類型是根據 line-height 來計算的。但事實是 對於內聯元素,vertical-align 與 line-height 雖然看不見,但實際上「處處都是」。其實咱們不少時候發現設置 vertical-align 屬性無效,這頗有可能就是 line-height 的緣由了,下面咱們來看兩個典型的例子。

  • Demo1 :任意一個塊級元素,裏面如有圖片,則塊級元素高度基本上都要比圖片的高度高
<div class="box">
 <img src="./panda.jpg" />
</div>
<style> .box { width: 300px; border: 1px solid #ddd; } img { width: 100px; height: 100px; } </style>
複製代碼

產生這種現象的緣由:空白節點、line-heightvertical-align屬性;圖片後放置空白節點 X,會發現圖片的基線是元素底部,與「空白節點」的基線對齊,那解決這種問題有如下幾個方法:

(1)將圖片設置爲 display:block (利用 vertical-align 的生效前提)

(2)將 vertical-align 設置爲 top,bottom,或者 middle 等值(利用屬性值的表現行爲)

(3)將 line-height 設置爲 0 (利用 line-height 爲 0 時,基線上移)

(4)將 font-size 設置爲 0 (若是 line-height 的值爲相對值)

(5)將 img 設置浮動或者絕對定位 (若是佈局容許的話)

  • Demo2:近似垂直居中
<div class="box">
  <span class="son"></span>
  x
</div>
<style> .box { width: 300px; height: 150px; line-height: 150px; font-size: 20px; border: 1px solid #ddd; position: relative; } // 繪製父元素的垂直中心線 .box::after { content: ""; position: absolute; display: block; width: 100%; height: 1px; background-color: red; top:0; bottom: 0; margin: auto; left: 0; } .son { display: inline-block; width: 100px; height: 100px; vertical-align: middle; background-color: purple; position: relative; } .son::after { content: ""; position: absolute; display: block; width: 100%; height: 1px; background-color: #317ffd; top:0; bottom: 0; margin: auto; left: 0; } </style>
複製代碼

如圖所示(爲了更明顯我使用了色塊來標識),當子元素(圖片)設置了 vertical-align:middle,並非絕對居中,而只能說是近似居中。子元素的垂直中心線與父級元素基線的位置往上二分之一 X 高度(X 的中心) 所在線對齊,通俗一點講,就是圖中紅線表示父元素的垂直中心線,藍線表示子元素的垂直中心線,能夠明顯的看到 藍線 與 X 的中心保持一致,但較紅線偏低。若是絕對居中的話,兩條線應該徹底重合。

爲何會產生這種現象呢?主要緣由在於文字具備下沉特性,從而致使藍線沒法絕對與紅線對齊。當文字大小足夠小時,咱們能夠忽略。從而近似的實現居中效果。可是文字越大,影響就越明顯。

那對於這樣的問題咱們要怎麼解決呢?如下提供幾種思路:

一、設置後面的 「空白節點 X 」 的垂直對齊方式也是 vertical-align:middle,然而,既然稱之爲 「空白節點」 就表示不會受非繼承特性的屬性影響,因此,根本無法設置 vertical-align:middle,除非你本身建立一個顯示的內聯元素或者僞元素。

二、「空白節點」 能夠受具備繼承特性的 CSS 屬性影響,因而,咱們能夠經過其餘東西來作調整,讓字符的中線和字符內容中心線在一塊兒,或者說在一個位置上就能夠了。設置父元素 font-size : 0 , 所以此時content area高度是 0 ,各類亂七八糟的線都在高度爲 0 的這條線上,絕對中心線和中線重合。效果以下:

這種經過 line-height 定高,元素 vertical-align:middle 垂直居中的方法不只適用於現代瀏覽器,連 IE 瀏覽器也是支持的,可是這裏只有在 IE7 中須要注意的是圖片後面須要換行或者空格,經驗證這個不是因爲標籤閉合引發的,可能只是一個 IE7 的 bug 吧。比較幸運的是,如今不少網站的兼容都是基於 IE9,因此能夠忽略這個問題啦。

<div><img src="xxx.jpg"><!-- 這裏要折行或空格 --></div>
複製代碼

擴展案例

  • 案例1:任意父級高度的垂直居中

咱們給父級設置 line-height 的值等於 height 的值,實現了近似垂直居中的效果。那若是父級的高度是隨着內容的變化而變化的怎麼辦?此時沒法給父級設置一個特定的值,也不能使用百分比,由於 line-height 是根據字體的大小來計算的。

好比下面這種狀況,整個盒子高度是肯定的,可是文本的內容不肯定。同時要求兩種表現形式相同,咱們要怎麼實現呢?

<ul>
  <li class="text-container">
    <span>我是單行文本我是單行文本</span>
  </li>
  <li class="text-container">
    <span>我是多行文本我是多行文本我是多行文本我是多行文本我是多行文本我是多行文本</span>
   </li>
 </ul>
<style> .text-container { height: 150px; text-align: center; vertical-align: middle; } .text-container:after { content: ""; display: inline-block; width: 0; height: 100%; vertical-align: middle; } span { vertical-align: middle; display: inline-block; max-width: 90%; max-height: 100px; overflow: hidden; } </style>
複製代碼

固然實現方式千千萬,既然咱們知道了 vertical-align 的原理。爲何不學以至用呢?按照以前的講解,咱們能夠藉助空白節點,空白節點咱們看不見,可是若是能夠給它設置一個高度,讓它與父級高度一致,就解決了這個問題。怎麼給高度呢?答案是藉助僞元素。那麼咱們解決這類問題就可使用如下步驟了:

  • 主體元素 inline-block 化
  • 0 寬度 100% 高度的輔助元素(僞元素)
  • ertical-align : middle
  • 案例2:實現多圖列表的兩端對齊

在作相似商品列表的佈局時,咱們時常須要每一行列表的實現兩端對齊。實現的方法有不少,這裏咱們用 display:inline-block + 輔助元素 來實現。

<dl class="container">
  <dt><img src="./7.jpg"/></dt>
  <dt><img src="./7.jpg"/></dt>
  <dt><img src="./7.jpg"/></dt>
  <dt><img src="./7.jpg"/></dt>
  <dt><i class="justify-fix"></i></dt>
  <dt><i class="justify-fix"></i></dt>
  <dt><i class="justify-fix"></i></dt>
  xxx
</dl>
<style> .container { text-align: justify; width: 400px; margin: 50px auto; border: 1px solid #ddd; line-height: 0; } dt { list-style: none; display: inline-block; width: 100px; } .container img { width:100px; height:100px; } .justify-fix { display: inline-block; width: 100px; outline: 1px dashed #317ffd; vertical-align: middle; } </style>
複製代碼

咱們會一眼就看到在圖片周圍處處都是空白空隙,那麼這些空隙是什麼緣由形成的呢?不少時候,複雜問題是由簡單問題組合而成的,那麼咱們能夠按照如下想法來簡化問題。

咱們能夠想象整個佈局只存在虛線框中的部分。大的部分都是由一塊一塊的虛線框中部分組合而成的。咱們會驚喜的發現這個現象就是上面所說的任意一個塊級元素,裏面如有圖片,則塊級元素高度基本上都要比圖片的高度高問題,那麼產生的緣由就知道了,是 line-height 與 vertical-align 之間關係產生的影響。

上面已經講過如何解決此類問題,咱們直接給父元素 line-height:0 ,這樣每一個虛線框中小的空隙就消失了。可是能夠明顯的看到底部有很大的空隙並無消除。爲了更清楚,我把佔位 i元素 outline 高亮下。而且添加一個空白節點 x。

最後一個 dt 與咱們手動添加的空白節點 X 的基線對齊。還記得前面說過的兩個 inline-block 排列錯位的例子嗎? 這個現象就是由 inline-block 基線問題引發的。正如圖中紅色框展現的,dt 的基線是元素底部,根據上面所講的,給佔位元素i加一個 vertical-align:bottom/top 屬性。而後就完美地解決了~

總結

本文講解了 vertical-align 的基本屬性以及各類表現,同時對一些實際應用中 vertical-align 無效現象作了簡單的分析闡述,併爲解決此類問題提供了思路。本文講解可能不全面,不成熟,歡迎在評論區留下寶貴評論,共同探討,共同進步。

參考文獻

CSS深刻理解vertical-align和line-height的基友關係

再次認識 vertical-align

vertical-align屬性與垂直居中

深刻理解css之vertical-align

推薦閱讀

前端工程實踐之可視化搭建系統(一)

多是最全的 「文本溢出截斷省略」 方案合集

圖文並茂,爲你揭開「單點登陸「的神祕面紗

招賢納士

政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 50 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。

若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「 5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com

相關文章
相關標籤/搜索