Vertical-Align,你應(yīng)該知道的一切

好炮捧,我們聊聊vertical-align庶诡。這個(gè)屬性主要目的用于將相鄰的文本與元素對齊。而實(shí)際上咆课,verticle-algin可以在不同上下文中靈活地對齊元素末誓,以及進(jìn)行細(xì)粒度的控制,不必知道元素的大小书蚪。元素仍然在文檔流中喇澡,因而其他元素可以根據(jù)它們大小的變化進(jìn)行相應(yīng)的調(diào)整。一個(gè)有用的例子就是居中圖標(biāo)與旁邊的文本殊校。

Vertical-Align是個(gè)怪物

可是晴玖,vertical-align有時(shí)候也很難搞,經(jīng)常導(dǎo)致困惑为流。好像有什么神秘的規(guī)則在起作用呕屎。比如,我們改變了某個(gè)元素的vertical-align而它的對齊方式卻并未改變艺谆,反倒是同一行的其他元素的對齊方式變了榨惰!我時(shí)不時(shí)地仍然會掉到vertical-align的坑里,絕望無助静汤。

遺憾的是,關(guān)于這方面的資料大都講得很膚淺居凶。尤其是針對布局的情況虫给。很多文章概念錯(cuò)亂,試圖把元素中的一切都垂直對齊侠碧。它們介紹了這個(gè)屬性的基本概念抹估,解釋了簡單情況下元素的對齊,卻沒涉及真正棘手的部分弄兜。

因此药蜻,我給自己設(shè)定了一個(gè)目標(biāo):徹底摸清vertical-align的行為。然后我就死啃W3C的CSS規(guī)范替饿,同時(shí)也嘗試了一些例子语泽。最終寫出了這篇文章。

好视卢,下面我們就開始吧踱卵。

對哪些元素可以使用Vertical-Align

vertical-align用于對齊行內(nèi)元素。所謂行內(nèi)元素据过,即display屬性值為下列之一的元素:

  • inline

  • inline-block

  • inline-table (本文未涉及)

其中惋砂,行內(nèi)元素(inline element)就是包含文本的標(biāo)簽妒挎。

行內(nèi)塊元素(inline-block element),顧名思義西饵,就是位于行內(nèi)的塊元素酝掩。可以有寬度和高度(可以由其內(nèi)容決定)眷柔,也可以有內(nèi)邊距庸队、邊框和外邊距。

行內(nèi)級元素會相互挨著排成行闯割。如果一行排不下彻消,就會在下方再建一行。所有行都會創(chuàng)建所謂的行盒子宙拉,行盒子裝著自己行中的所有內(nèi)容宾尚。內(nèi)容的高度不同,行盒子的高度也不同谢澈。在下面的示意圖中煌贴,行盒子的頂部和底部用紅色點(diǎn)線表示。

image.gif

這些行盒子限定了我們可以影響的范圍锥忿。在行盒子內(nèi)部牛郑,可以通過vertical-align來對齊個(gè)別元素。那么敬鬓,相對于什么來對齊元素呢淹朋?

基線與外邊界

垂直對齊最重要的參考點(diǎn),就是相關(guān)元素基線钉答。某些情況下础芍,行盒子的上下外邊界也會成為參考點(diǎn)。下面我們就來看一看相關(guān)元素類型的基線和外邊界数尿。

行內(nèi)元素

image.gif

這里有三行文本緊挨著仑性。紅線表示行高的頂邊和底邊,綠線表示字體高度右蹦,藍(lán)線表示基線诊杆。左邊這一行,行高與字體高度相同何陆,因此上下方的紅色和綠線重疊在了一起晨汹。中間一行,行高是font-size的兩倍甲献。右邊一行宰缤,行高為font-size的一半。

行內(nèi)元素的外邊界與自己行高的上、下邊對齊慨灭。行高比font-size小不小并不重要朦乏。因此上圖中紅線同時(shí)也就表示外邊界。

行內(nèi)元素的基線是字符恰好位于其上的那條線氧骤,也就是圖中的藍(lán)線呻疹。大致來說,基線總是穿過字體高度一半以下的某一點(diǎn)筹陵」舸福可以參考W3C規(guī)范中詳細(xì)的定義。

行內(nèi)塊元素

image.gif

從左到右:包含流內(nèi)內(nèi)容(“c”)的行內(nèi)塊朦佩、包含流內(nèi)內(nèi)容且設(shè)置了溢出(overflow: hidden)的行內(nèi)塊和未包含流內(nèi)內(nèi)容(但內(nèi)容區(qū)有高度)的行內(nèi)塊并思。紅線表示外邊距的邊界,黃色是邊框语稠,綠色的內(nèi)邊距宋彼,藍(lán)色是內(nèi)容區(qū),藍(lán)線是每個(gè)行內(nèi)塊元素的基線仙畦。

行內(nèi)塊元素的外邊界即其外邊距盒子的上输涕、下兩邊,也就是圖中的紅線慨畸。

行內(nèi)塊元素的基線取決于元素是否包含流內(nèi)內(nèi)容:

  • 有流內(nèi)內(nèi)容的行內(nèi)塊元素莱坎,基線就是正常流中最后內(nèi)容元素的基線(左)。這個(gè)最后元素的基線是按照它自己的規(guī)則找到的寸士。

  • 有流內(nèi)內(nèi)容但overflow屬性值不是visible的行內(nèi)塊元素檐什,基線就是外邊距盒子的底邊(中)。也就是與行內(nèi)塊元素的下外邊界重合碉京。

  • 沒有流內(nèi)內(nèi)容的行內(nèi)塊元素厢汹,基線同樣是外邊距盒子的底邊(右)。

行盒子

image.gif

這張圖前面出現(xiàn)過谐宙。但這次我們畫出了行盒子的文本盒子的上、下邊(綠色界弧,下面詳細(xì)介紹)還有基線(藍(lán)色)凡蜻。同時(shí),還用灰色背景表示了文本元素的區(qū)域垢箕。

行盒子的頂邊與該行中最頂部元素的頂邊重合划栓,底邊與該行中最底部元素的底邊重合。因此圖中的紅線表示的就是行盒子条获。

行盒子的基線是個(gè)變量:

CSS 2.1沒有定義行盒子的基線忠荞。

在使用vertical-align時(shí)這一塊應(yīng)該是最令人困惑的了。也就是說,基線畫在哪里需要滿足很多條件委煤,比如要符合vertical-align指定的條件堂油,同時(shí)還要保證行盒子高度最小。這是個(gè)自由變量碧绞。

因?yàn)樾泻凶拥幕€并不可見府框,所以有時(shí)候不容易確定它的位置。但實(shí)際上有個(gè)簡單的辦法可以令其可見讥邻。只要在相關(guān)行的開頭加上一個(gè)字母迫靖,比如上圖中開頭的“x”即可。如果這個(gè)字母沒有被設(shè)置對齊兴使,那么它默認(rèn)就位于基線之上系宜。

圍繞基線的是行盒子中的文本盒子》⑵牵可以簡單地把文本盒子看成行盒子內(nèi)部未經(jīng)對齊的行內(nèi)元素盹牧。文本盒子的高度等于其父元素的font-size。因此欠母,文本盒子只是用來盛放未經(jīng)格式化的文本的欢策。上圖中的綠線表示的就是文本盒子。由于文本盒子與基線關(guān)聯(lián)赏淌,所以基線移動它也會跟著移動踩寇。(W3C規(guī)范里稱這個(gè)文本盒子為strut。)

終于把最難的部分講完了六水。現(xiàn)在俺孙,我們已經(jīng)知道了對齊相關(guān)的一切要素。下面簡單總結(jié)一下最重要的兩點(diǎn)掷贾。

  • 有一個(gè)區(qū)域叫行盒子睛榄。行盒子中的內(nèi)容可以垂直對齊。行盒子有基線想帅、文本盒子场靴,還有上邊和下邊。

  • 還有行內(nèi)元素港准,也就是可以被對齊的對象旨剥。行內(nèi)元素有基線,以及上邊和下邊浅缸。

Vertical-Align的值

使用vertical-align轨帜,前面提到的參考點(diǎn)就會按照某種關(guān)系被設(shè)置好。

對齊行內(nèi)元素的基線和行盒子的基線

image.gif
  • baseline:元素基線與行盒子基線重合衩椒。

  • sub:元素基線移動至行盒子基線下方蚌父。

  • super:元素基線移動至行盒子基線上方哮兰。

  • <百分比值>:元素基線相對于行盒子基線向上或向下移動,移動距離等于line-height的百分比苟弛。

  • <長度值>:元素基線相對于行盒子基線向上或向下移動指定的距離喝滞。

相對于行盒子的基線對齊元素的外邊界

image.gif
  • middle:元素上、下邊的中點(diǎn)與行盒子基線加上x-height的一半對齊嗡午。

相對于行盒子的文本盒子對齊元素的外邊界

image.gif

還有兩種情況是相對于行盒子的基線對齊囤躁,因?yàn)槲谋竞凶拥奈恢糜尚泻凶拥幕€決定。

  • text-top:元素的頂邊與行盒子的文本盒子的頂邊對齊荔睹。

  • text-bottom:元素的底邊與行盒子的文本盒子的底邊對齊狸演。

相對于行盒子的外邊界對齊元素的外邊界

image.gif
  • top:元素的頂邊與行盒子的頂邊對齊。

  • bottom:元素的底邊與行盒子的底邊對齊僻他。

當(dāng)然宵距,正式的定義在W3C的規(guī)范里。

為何Vertical-Align的行為如此乖張

下面我們看看在某些情況下的垂直對齊吨拗。特別是一些容易出錯(cuò)的情況满哪。

居中圖標(biāo)

有一個(gè)問題一直困擾著我。有一個(gè)圖標(biāo)劝篷,我想讓它與一行文本垂直居中哨鸭。如果只應(yīng)用vertical-align: middle好像不行,比如這個(gè)例子:

image.gif

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<span class="icon middle"></span>

Centered?

<span class="icon middle"></span>

<span>Centered!</span>

<style type="text/css">

.icon { display: inline-block;

        /* size, color, etc. */ }

.middle { vertical-align: middle; }

</style>

</pre>

還是同一個(gè)例子娇妓,只不過這次多了一些輔助線:

image.gif

這次可以看清問題所在了像鸡。因?yàn)樽髠?cè)的情況是文本沒對齊,而是仍然位于基線之上哈恰。應(yīng)用vertical-align: middle只估,實(shí)際上會導(dǎo)致圖標(biāo)中心與不出頭小寫字母的中心(x-height的一半)對齊,所以出頭的字母會在上方突出出來着绷。

右側(cè)蛔钙,仍然是對齊整個(gè)字體區(qū)的垂直中點(diǎn)。結(jié)果文本基線稍稍向下移動了一點(diǎn)荠医,于是就實(shí)現(xiàn)了文本與圖標(biāo)完美對齊吁脱。

行盒子基線的移動

這是使用vertical-align時(shí)一個(gè)常見的坑:行盒子基線的位置會受到其中所有元素的影響。假設(shè)一個(gè)元素采用的對齊方式會導(dǎo)致行盒子移動彬向。由于大多數(shù)垂直對齊(除top和bottom外)豫喧,都相對于基線計(jì)算,因此這會導(dǎo)致該行所有其他元素重新調(diào)整位置幢泼。

下面是幾個(gè)例子。

  • 如果行內(nèi)有一個(gè)很高的元素讲衫,這個(gè)元素上方和下方都沒有空間了缕棵,此時(shí)要與行盒子的基線對齊孵班,就必須讓它移動。矮盒子是vertical-align: baseline招驴。左側(cè)的高盒子是vertical-align: text-bottom篙程,而右側(cè)的高盒子是vertical-algin: text-top”鹄澹可以看到虱饿,基線帶著矮盒子移動到了上方。
image.gif

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<span class="tall-box text-bottom"></span>

<span class="short-box"></span>

<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>

</pre>

在通過vertical-align的其他值對齊一個(gè)較高的元素時(shí)触趴,也會出現(xiàn)同樣的現(xiàn)象氮发。

  • 即使設(shè)置vertical-align為bottom(左)和top(右),也會導(dǎo)致基線移動冗懦。這就很奇怪了爽冕,因?yàn)榇藭r(shí)根本不關(guān)基線什么事。
image.gif

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<span class="tall-box bottom"></span>

<span class="short-box"></span>

<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>

</pre>

  • 把兩個(gè)較大的元素放在一行并垂直對齊它們披蕉,基線也會移動以匹配兩種對齊颈畸。然后,行的高度會調(diào)整(左)没讲。再增加一個(gè)元素眯娱,但該元素對齊方式?jīng)Q定了它不會超出行盒子的邊界,所以行盒子不會調(diào)整(中)爬凑。如果新增的元素會超出行盒子的邊界徙缴,那么行盒子的高度和基線就會再次調(diào)整。在這例子中贰谣,前兩個(gè)盒子向下移動了(右)娜搂。
image

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<span class="tall-box text-bottom"></span>

<span class="tall-box text-top"></span>

<span class="tall-box text-bottom"></span>

<span class="tall-box text-top"></span>

<span class="tall-box middle"></span>

<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>

</pre>

行內(nèi)元素下面可能會有一個(gè)小間隙

看看這個(gè)例子:對列表元素的li應(yīng)用vertical-align。

image

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<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>

</pre>

我們看到吱抚,列表項(xiàng)位于基線上百宇。基線下面有一個(gè)小間隙秘豹,用于文本的下伸部分携御。怎么辦?只要把基線向上移開一點(diǎn)就行了既绕,比如用vertical-align: middle:

image

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<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>

</pre>

有文本內(nèi)容的行內(nèi)塊不會出現(xiàn)這種情況啄刹,因?yàn)閮?nèi)容已經(jīng)把基線向上移了。

行內(nèi)元素間的間隙會破壞布局

這主要是行內(nèi)元素本身的問題凄贩。由于vertical-align必然會遇到行內(nèi)元素誓军,所以有必要了解一下。

在前面列表項(xiàng)的例子中也可以看到這個(gè)間隙疲扎。這個(gè)間隙來自你的標(biāo)記中行內(nèi)元素間的空白昵时。行內(nèi)元素間的所有空白會折疊為一個(gè)捷雕。如果我們要通過width: 50%實(shí)現(xiàn)并排放兩個(gè)行內(nèi)元素,那這個(gè)空白就會成為障礙壹甥。因?yàn)橐恍蟹挪幌聝蓚€(gè)50%再加一個(gè)空白救巷,結(jié)果就會折行(左)。要?jiǎng)h除這個(gè)間隙句柠,需要在HTML中通過注釋刪除空白(右)浦译。

image.gif

<pre class="" style="margin: 0px; padding: 1em; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; border-width: 0px; border-style: initial; border-color: initial; overflow: auto; background-color: rgb(45, 45, 45); color: rgb(204, 204, 204);">

<div class="half">50% wide</div>

<div class="half">50% wide... and in next line</div>

<style type="text/css">

.half { display: inline-block;

      width: 50%; }

</style>

</pre>

Vertical-Align揭秘

好了,就這些溯职。一旦了解了規(guī)則精盅,就沒有那么復(fù)雜了。如果vertical-align沒有達(dá)到效果缸榄,只要問下面的問題就能找到癥結(jié)所在:

  • 行盒子的基線和上渤弛、下邊界在哪兒?

  • 行內(nèi)元素的基線和上甚带、下邊界在哪兒她肯?

據(jù)此就可以找到問題的解決方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鹰贵,一起剝皮案震驚了整個(gè)濱河市晴氨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碉输,老刑警劉巖籽前,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異敷钾,居然都是意外死亡枝哄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門阻荒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挠锥,“玉大人,你說我怎么就攤上這事侨赡”妥猓” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵羊壹,是天一觀的道長蓖宦。 經(jīng)常有香客問我,道長油猫,這世上最難降的妖魔是什么稠茂? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮情妖,結(jié)果婚禮上主慰,老公的妹妹穿的比我還像新娘嚣州。我一直安慰自己,他們只是感情好共螺,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著情竹,像睡著了一般藐不。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秦效,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天雏蛮,我揣著相機(jī)與錄音,去河邊找鬼阱州。 笑死挑秉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苔货。 我是一名探鬼主播犀概,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼夜惭!你這毒婦竟也來了姻灶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤诈茧,失蹤者是張志新(化名)和其女友劉穎产喉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敢会,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡曾沈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸥昏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塞俱。...
    茶點(diǎn)故事閱讀 40,973評論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖互广,靈堂內(nèi)的尸體忽然破棺而出敛腌,到底是詐尸還是另有隱情,我是刑警寧澤惫皱,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布像樊,位于F島的核電站,受9級特大地震影響旅敷,放射性物質(zhì)發(fā)生泄漏生棍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一媳谁、第九天 我趴在偏房一處隱蔽的房頂上張望涂滴。 院中可真熱鬧友酱,春花似錦、人聲如沸柔纵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搁料。三九已至或详,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郭计,已是汗流浹背霸琴。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昭伸,地道東北人梧乘。 一個(gè)月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像庐杨,于是被迫代替她去往敵國和親选调。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評論 2 361

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

  • 有些東西我們經(jīng)常用辑莫,但是我們卻并不了解它的原理学歧,所以一旦換了場景,好多東西就不知道該怎么用了各吨。最近一直很糾結(jié)ver...
    朱小維閱讀 4,951評論 8 34
  • vertical-align這個(gè)屬性主要目的用于將相鄰的文本與元素對齊枝笨。而實(shí)際上,verticle-algin可以...
    oWSQo閱讀 462評論 0 0
  • H5移動端知識點(diǎn)總結(jié) 閱讀目錄 移動開發(fā)基本知識點(diǎn) calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇閱讀 4,531評論 0 26
  • 移動開發(fā)基本知識點(diǎn) 一.使用rem作為單位 html { font-size: 100px; } @media(m...
    橫沖直撞666閱讀 3,485評論 0 6
  • 離2019元旦還差四十來小時(shí)揭蜒,可是這一次瑞雪??卻再也等不及地來約横浑,而且還是來得如此瀟瀟灑灑,著實(shí)讓期盼它的人兒欣...
    MisLuo閱讀 131評論 0 0