標籤:

這樣理解 CSS vertical-align,可謂釋然

提綱:

  • 前言
  • 建立全局觀
  • 實驗代碼與關鍵名詞解釋
  • vertical-align 含義水到渠成
  • 案例分析
  • 結語

前言

最近我在自學 CSS (cascading style sheets), 發現這個話題還真是相當複雜。複雜的地方不在於它不斷增加的語法多樣性,而在於那些看似簡潔的語法背後、影響網頁元素最終呈現的大量互相交織、互相影響的隱性因素。這些隱性因素,單從 CSS 語法上是無法直接察覺的,得有明眼人指導,加上自己動手反覆嘗試才能逐步探查清楚。

Vertical-align, 一個看似普通的 CSS 屬性(property),用來調整一塊文本的頂部對齊、底部對齊或是居中對齊,其實裡頭大有名堂,這是隱性因素大行其道的地方。這兩天玩弄這個屬性的過程還發現了 Chrome 71 (2019.02) 在這個屬性上犯的 bug ,真是意外。剛開始沒意識到這是 bug,以為是我自己理解有誤,但對照了 Firefox 65 後,認為這應該就是 Chrome 的 bug,本文後頭將展示之([CASE 3.1])。因此,世界上有兩份完全不同的瀏覽器實現是多麼重要。

我學習 CSS 的參考書有兩本:

  • [CSSID] Manning - CSS in Depth (2018),是塑造 CSS 全局觀的書,超棒,我給十分。不過此書偏偏沒講 vertical-align.
  • [CSSDG] OReilly - CSS: The Definitive Guide, 4th Edition (2017),這本歷史其實很悠久了,從 2000 的第一版不斷擴寫而來,我只給七分,因為它缺乏全局觀,像流水帳,更適合當字典來查。

網上講 vertical-align 的文章重床疊架。但我相信我的這篇是獨特的,因為我相信我自己在寫這篇文章的過程中為自己塑造了 vertical-align 的全局觀。全局觀為什麼重要,因為它能使我們擺脫盲人摸象的處境,網上的很多文章可能就沒有擺脫這種處境。

當然,我不敢說我這裡講的內容完全正確,細節上可能有些許偏差,畢竟 CSS 的複雜性擺在那裡,我這篇文章更像是提供了一小塊實驗場,我們可以藉助其驗證陳述的對錯。

【澄清關於 vertical-align 的歧義】

如果你去看 vertical-align 的官方文檔,它的第一句話是:

The vertical-align CSS property sets vertical alignment of an inline or table-cell box.

但我要告訴你,vertical-align 此處是有歧義的,更準確地說,它是一詞兩用,你體會到了嗎?

打個比方,「龍頭」這個詞,其實它有獨立的兩個意思,「自來水龍頭」和「行業龍頭」。回到 vertical-align,其實是兩個獨立場景用了同一個屬性名。

  • 場景一,不妨叫它 align-me-to-parent 。我們在一個 inline 性質的子元素上設定該屬性,讓這個子元素用一種特定的規則跟父元素進行對齊。
  • 場景二,不妨叫它 align-my-children。我們在一個 table-cell 元素(作為父元素)上設定該屬性,讓它的子元素在單元格內浮頂、沉底或居中顯示。

這兩種場景是完全互相獨立的,按理說應該給它們起不同的屬性名,只不過,CSS 的規範制定者偷了個懶,用了相同的名字,好在這兩種場景是不會交叉的,意即,一個元素不可能既是 table-cell 又是個 inline (<span>, <img> 等),一詞兩用也就不會有衝突了。

順便說一句,場景二的 vertical-align 有個孿生屬性,叫 text-align,其取值可以是 left, center, right, 用於指示它裡頭的子元素在水平方向上靠左、居中、或靠右對齊。然而,場景一卻沒有類似的孿生屬性,是啊,一個 inline element 豈有水平方向上任意找人對齊的道理?

本文討論的 vertical-align 完全是 align-me-to-parent 這種場景;至於 align-my-children 那個場景則簡單得多,本文就不費筆墨了。本文後頭提及的 vertical-align ,都是指場景一的。

接下來,文章比較長,需要一些耐心。

建立全局觀

這裡我必須先展示一個表格,叫它 VA-table 吧,該表格是獲得 vertical-align 全局觀的關鍵。後頭分析具體案例時,你需要回頭來查這張表格。

表格中出現了一些陌生的名詞,特別是 inlinebox 和 linebox ,它們就是 vertical-align 背後隱性的關鍵概念,我下面慢慢解釋。

這個 VA-table 還傳達了一些重要的隱性事實。

【事實一】vertical-align 是設在 inline 性質的元素上的(而非設在 block 性質的元素上);而且,被設了 vertical-align 的元素,你應該將它的父元素也看成是 inline 性質的。

比如說,html 中寫

<p><span class="A">AAA <span class="B">BBB</span> !</span></p>

A 和 B 都是 inline 性質的,因此在 B 上設 vertical-align:xxx 完全合理。

再比如,

<p class="C">CCC <span class="D">DDD</span> !</p>

這回 C 裡頭嵌套著 D,D 是 inline 的沒問題,但 D 的父元素是個 <p>,它是個 block element,那該如何解釋呢?此時,你應該想像 D 外頭還是套著一個隱式的 inline 元素,畢竟 D 的兩旁有文字嘛(前有 "CCC",後有感嘆號),你得想像這些文字構成了一個 inline 父元素,好比 CCC 和感嘆號是被包在一個 <span> 裡頭那樣。

就算 <p> 元素自身不含有任何文本(不運算元元素裡頭的文本),你也應該想像它本來是有文字的,有文字就有對齊點了,然後將那些文字刪除,先前確定的對齊點則會繼續起作用。這個想像有點抽象,不急,可以回過頭再想。

如此想像的理由是,只有 inline 元素,才有所謂的 baseline, inlinebox, linebox 概念,這樣才能跟 VA-table 的內容對上號。

【事實二】當你給一個元素設上 vertical-align:xxx 時,你指定的其實不是唯一一個參數,而是兩個隱式的參數,即 VA-table 中「子元素對齊點」和「父元素對齊點」這兩個隱式參數。

舉例說,你給子元素設了 vertical-align:text-top , 那麼你實質上設定的其實是兩個參數:

  • 你挑中了子元素自己的 inlinebox top 。
  • 同時你挑中了父元素的 linebox top 。

預先提一句: vertical-align 的一個參數值,實質卻是決定了自己身上的一個值以及父元素身上的一個值,那麼該參數值的命名傾向是自己還是父元素呢?縱觀表格,我們發現它傾向的其實是父元素,vertical-align:text-top 就是典型的例子,此處的 text-top 暗示的是父元素的 text-top 而非自己的 text-top 。

實驗代碼與關鍵名詞解釋

為了講述我的理解方法,我需要拿一個例子為基礎。該例子由 CSSDG CH6.2 p223 的例子改裝而來。

ch0616-chj1.html

<!doctype html>
<html>
<head>
<title>ch0616-chj1.html</title>
<style type="text/css">
body {
width: 500px;
margin: 0px;
}
p {
margin: 0px; /* if omit, margin-top will equal to font-size */
}
.myspan {
font-size: 24px;
line-height: 120px; /* same as line-height:5 */
border: 6px solid #8f8;
}
.feeder {
vertical-align: bottom;
}
</style>
</head>
<body>

<p><span class="myspan">This paragraph, as you can see quite clearly, contains
a <img alt="tall" class="feeder" src_="data:image/gif;base64,R0lGODlhHgA8AOb/AP////7+/v39/fv7+/r6+vj4+Pb29vT09PLy8vDw8O7u7u3t7ezs7Orq6ujo6Obm5uXl5ePj4+Hh4d/f393d3dvb29nZ2dfX19XV1dPT09LS0tHR0dDQ0M7Ozs3NzczMzMbGxr+/v7i4uLKysrGxsa6urqysrKqqqqmpqaenp6ampqSkpKOjo6GhoaCgoJ+fn56enp2dnZycnJKSkpGRkYmJiYiIiIeHh4SEhIKCgoCAgH9/f35+fn19fXx8fHt7e3p6enl5eXh4eHR0dHNzc3JycnFxcXBwcG9vb25ubm1tbWxsbGpqamlpaWhoaF5eXl1dXVpaWk9PT0pKSkBAQD8/Pz4+Pj09PTw8PDs7Ozo6Ojk5OTg4ODc3NzY2NjU1NTQ0NDAwMC4uLi0tLR8fHx4eHh0dHRAQEA8PDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAHgA8AAAH/4BpgoOEhYaHgx2Ki4yNjo+Cj5KTjJGUl46CFx0vT0ieoEg3HZulpKemF5EXSIhdipuwi7GnmpxIuIJSnzcXpb6kwL6lmsO+ginGysvGxc1pL8zSzxMX1dXI1trX293YaRPcE8jh4t7eguXl2ert7uvg7eTv9PAPE/f3giX4/fn+APWleUCwILKCCBMqfCBI4b6FEBE2jEgRoiAFCTFifDFkCL6KDxQ0VECSZMiQZATVKMmyZciLLUuOGCQlpk2RaW4qeJJGTCSdLAUZsDkuzYWUN4CSNHDRgNOnBmr0VNCKDNSrThUwTYPVacoaBlSlAdH1qlCsM9Mg2bEDTZonZf+hCgJwFQBPQ2fiOgUgFIBfvw/OvGXLdt/fw34N8E2TmC6AF2nQIJaSRoriy44VL0YMwCeSv4pLXOR8eC7p06j/mkb9YkeI1KUZp66SZgds1bJR07Z9ezNmzZd3H/6deTHxvYp3Py1OfC5Wuk6FX9Z7Nq5yvU+rl6U9BHt2rlrDDx2vfKn481uVcjcPFKZO2oZG3HR/E34h+TZHntR4MqTN/ftdRBFGBNUwRAkEEZjQRCA9wB1FDIL0YEQRVkQbEhAOVE87XaQxxD3vMBTPhuV0iMSG6ZBYoloojqiiide848w0w5ioDTMz0niBjdPkSGOHhiQzjI/TAFnIC8GIhQkcI78Ec4oitqSCypSUbGLJkkteieUliHTpJSGBAAA7" /> image and
a <img alt="short" class="feeder" src_="data:image/gif;base64,R0lGODlhHwALANX/AP////39/fr6+vr6+fr5+vn6+vn5+vb29vLy8u7u7u7u7e7t7u7t7e3u7u3u7e3t7unp6ebl5ubl5eXm5uXm5eXl5uXl5eLi4t7e3d7d3d3e3d3d3t3d3dnZ2dXV1dLR0dHS0dHR0tHR0c7OzszMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAHwALAAAGhcCScEgsGo/E0cjjwWAikUTicABYrVQp1MlUCpXLJjRKrWKzY0zXW1J6hpGStFQVWoeJeHL05Tefcgl0JXcHdIJbJWt9byWAQ4Z3AHgRTopgjE0lcXORk5OGaYoebGyOcVF0k4SgiJWXpWFOT1JUVwBlWrOLbW5iULVmWFpbTKR8SMnKREEAOw==" /> pic,
and then some text which is not tall.</span></p>

</body>
</html>

在 Chrome 71 中,真實顯示效果如下:

(根據你給瀏覽器設定的默認字體不同,顯示效果會有所差異,下圖用的 "Segoe UI" 16px 字體。)

我費力地加了以下標註,用來解釋很多相關的概念。

BIGMARK1:

BIGMARK1

以上 html 的基本情況是:

  • Html 文檔的主體是一行文字,「This paragraph, as you can see ... which is not tall.」。
  • 文字的 font-size 被設為 24px,然而,我故意將 line-height 設得很大,120px,導致前後兩個顯示行的行距很大,以方便觀察。
  • 粗的綠線是文字塊的 border (HTML DOM 術語),用 CSS border 屬性生成的。上下 border 之間的高度(不包括綠線自身),被稱為 textbox 高度,該值一般比會比 font-size 值大幾個像素,具體大 5 個像素還是 8 個像素,依選用的 font-family 不同而不同。 。
  • 第二個顯示行中,插入了兩處 <img> 元素。要知道,<img> 元素也是 inline 性質的,因此 <img> 也可以被設定 vertical-align 屬性,再由於 <img> 元素的上下邊界是「清晰」的,這也有利於觀察。

現在開始解釋 linebox 和 inlinebox ,它們是相互交織的兩個概念,要小心理解。你看其他地方的資料的話,他們會寫成 "line box" 和 "inline box" ,但我喜歡把兩個詞連在一起,以清晰地暗示它們各自是一個語素,而且表示專有的意思。

【 linebox 】 本例 html 的主體文字字元數不算多,本來可以顯示在同一行的,但,我故意地將 <body> width 限定成 500px,讓這些文字打斷成三個顯示行。其目的是,每個顯示行各自形成了一個 linebox 。BIGMARK1 圖中的三個 linebox 高度都是 120px 。這裡插一個問題,同一個 <span> 元素形成的三個 linebox 有沒可能是不同的高度呢?有可能,後面會舉例。

【 inlinebox 】主體文字行寫在了 .myspan 元素裡頭,這個 .myspan 元素形成了唯一一個 inlinebox 。換言之,一個 inlinbox 的文字內容是可以被拆分在好幾個顯示行中的。

【inlinebox 的高度如何確定?】由一個 inline 元素的 line-height 值來確定。比如,html 代碼中寫了 line-height: 120px; 它使得 .myspan 的 inlinebox 高度變成 120px,什麼意思呢?當從左到右顯示這串文本到需要換行的時候,第二行的文字呈現不是緊貼在第一行的下方,而是要避開第一行已經佔據的 line-height 空間。

【linebox 的高度如何確定?】這要一個顯示行、一個顯示行地考察,因為每個顯示行對應著不同的 linebox 實例嘛。

感性理解是: 拿出任意一個顯示行來看,裡頭可能由不同字型大小的文字組成,大的字型大小會撐大當前顯示行的 linebox;如果還有 <img> 元素夾雜其中,那麼過高的 <img> 也會撐大當前顯示行。圖片作為一種 inline 元素,圖片的像素高度就是它的 inlinebox 高度。

更準確地說:真正撐大 linebox 的不是裡頭文字的字型大小(字型大小由 font-size 屬性值決定),而是文字上附著的 line-height 外殼。該外殼是隱形的,目前 F12 DevTools 裡頭無法直接顯示它,可以想像 line-height 給文字包上了一層透明的水晶外殼,雖然看不見,但卻佔據著排版空間。舉例,一個 12px 的 font-size 附上誇張的 80px 的外殼,比 16px 的 font-size 附上溫和的 24px 外殼,更能夠撐大 linebox 。

還有,linebox 高度會受角標的影響。比如,編排數學課本時,會出現 x2 這樣的寫法,我們假定 a 和 2 用相同字體、字型大小以及相同高度的外殼,那麼,由於 2 呈現為上角標,結果就使得 2 的外殼將 linebox 的上邊界撐大了。在 CSS 中,當我們將 2 這個字元從正常位置抬高到上角標位置時(比如上抬了 10px),2 的 line-height 外殼是不折不扣地被同步往上抬升了 10px ,導致整個 linebox 被撐大了 10px (假定原先的 2 已經跟 linebox 頂部齊平了的話)。如果好奇的話,可以瞄一眼具體的寫法:

<span>x<span stylex="vertical-align: 10px">2</span></span>

當然,如果你可以將 10px 改成一個巨大的值,比如說 200px,那麼,『2』 所在的這個 linebox 將變得巨大,『2』 高懸在天花板上,下方是接近 200px 的一大片空白,然後 x 站在地板上。

可以打個比喻,一個 linebox 像是一個隧道,inlinebox 像是隧道中運輸的一個個小水晶塊,有的水晶塊很高大,有的水晶塊要求飄在空中、跟隧道地面保持很大的落差,有的水晶塊要求離隧道地面很近,滿足全部水晶塊要求的最小隧道高度,就是 linebox 的高度。父元素裡頭嵌套子元素,相當於父元素這個大水晶塊裡頭嵌套著小的水晶塊,此時可以將水晶塊想像成空心的。但注意,html 的元素嵌套是邏輯上嵌套,而不是物理尺寸嵌套,因此小水晶塊裡頭嵌套更大的水晶塊是可以的。

就 ch0616-chj1.html 的例子,

  • .myspan 指定了 line-height:120px ,表示 inlinebox 為 120px,因此 linebox 的高度最少最少也有 120px。
  • 我們用的那個 TALL 圖片高度只有 60px,且在 vertical-align:bottom 時沒有出現飄得過高或沉得過低的情況,結果 linebox 沒有被額外撐大,linebox 也等於 120px。
  • 現在考察一下 inlinebox 的 120px 都用在什麼地方了。其中因為 font-size:24px 佔去了 24px,剩下 96px,相當於行間距(英文叫 leading)。CSS 規定這剩下的 96px 在 24px 文字實體的上下各分配一半,上面分到 48px,下面分到 48px。換言之,文字實體永遠處在它自己所在水晶塊的中央,不論自己或別人的 line-height 用什麼值,這個規則鐵打不變。

現在可以說 baseline 了,就 ch0616-chj1.html ,.myspan 的例子,baseline 就是 24px 的 font-size 佔位中,最底下的那行像素。

【對齊點】有了以上 inlinebox 和 linebox 的定義,我就可以引入對齊點的概念了。(對齊點是我自己發明的提法)

圖中標出了常用的六個對齊點。

  1. linebox top 是 linebox 的上邊緣。
  2. linebox bottom 是 linebox 的下邊緣。
  3. inlinebox top 是 inlinebox 的上邊緣。
  4. inlinebox bottom 是 inlinebox 的下邊緣。
  5. baseline 就是它自身。
  6. middle 是文字身體內大約中間高度。CSSDG p225 說,該高度的準確提法是,baseline 上方 1/4 em 處。
  7. text-top 和 text-bottom,圖中粗綠線所圍起的文本顯示區的上邊緣和下邊緣(該區域不包含綠線本身)。

vertical-align 含義水到渠成

當我們給一個元素(子元素)設定 vertical-align 時,它讓瀏覽器產生的動作是:

  • 根據該值去 VA-table 中查找 子元素對齊點父元素對齊點 這兩個隱式參數值。
  • 父元素不動,移動子元素,讓 子元素對齊點父元素對齊點 對齊。

提示:我這裡表達為「子元素向父元素對齊」,而非「子元素和父元素對齊」,請仔細體會兩者的細微差別。

舉例說,你給子元素設了 vertical-align:text-top , 查表得知,子元素對齊點是 inlinebox top, 父元素對齊點是 linebox top 。那麼實質動作是:

  1. 確定子元素此時所處的 linebox 是哪個。
  2. 確定父元素在這個 linebox 中的上邊緣(linebox top)。
  3. 確定子元素自身的 inlinebox top 。
  4. 調整子元素的上下位置,讓子元素的 inlinebox top 對準父元素的 linebox top 。

這裡有一點額外的規則:當我們將 <img> 這種 inline 元素塞到 linebox 裡頭時,<img> 的對齊點實際上只有三個(沒有 VA-table 列的那麼多)。這裡頭的規則是,

  • <img> 子元素的 inlinebox top, 即是其上邊緣。
  • <img> 子元素的 inlinebox bottom 和 baseline 即是其下邊緣。
  • <img> 子元素的 middle 對應著圖片垂直方向的中心點。

案例分析

【案例一】

在 Chrome 71 中打開 ch0616-chj1.html , 同時用 F12 DevTools 調整 .feeder 中的 vertical-align 值,看各種對齊的效果,完全符合 VA-table 的列示。

【案例二,linebox 大於 inlinebox 的例子】

tall2x.html

<!doctype html>
<html>
<head>
<title>tall2x.html</title>
<style type="text/css">
:root {
box-sizing: border-box;
}

*,
*::before,
*::after {
box-sizing: inherit;
}

body {
width: 500px;
margin: 0px;
}
p {
margin: 0px; /* if omit, margin-top will equal to font-size */
}
.myspan {
font-size: 24px;
line-height: 120px; /* same as line-height:5 */
border: 6px solid #8f8;
}
.feeder {
vertical-align: baseline;
}
.alignmark { /* as inlinebox */
position: fixed;
border-top: 1px solid #80c0ff;
border-bottom: 1px solid #80c0ff;
left: 0px;
width: 500px;
top: 188px; /* 120+68 */
height: 120px;
}
.linebox {
border-top: 1px dashed #ff40c0;
border-bottom: 1px dashed #ff80e0;
top: 120px; /* 1st lineboxs height */
height: 189px; /* 140(tall2x)+48 + casual 1 */
}
.baseline {
top: 260px; /* 120+140 */
border-top: 1px solid #ccc;
border-bottom: 0px;
}
</style>
</head>
<body>

<p>
<span class="myspan">This paragraph, as you can see quite clearly, contains
a <img class="feeder" src="tall2x.png" width="30" height="140" /> image and
a <img style="vertical-align:top" src="short.png" width="31" height="11" />
<img style="vertical-align:bottom" src="short.png" width="31" height="11" /> pic,
and then some text which is not tall.</span>
</p>

<div class="alignmark"></div>
<div class="alignmark linebox"></div>
<div class="alignmark baseline"></div>

</body>
</html>

為了讓代碼看起來短一些,我將內嵌的圖片內容移到外部了。

  • tall2x.png (30*140) i.stack.imgur.com/wweHl
  • short.png (31*11) i.stack.imgur.com/JVBAT

當然,你可以自行製作同等寬高的圖片來達到相同的效果。

運行效果圖解:

相比於 ch0616-chj1.html , tall2x.html 的變化如下.

.myspan 文本行的 line-height 不變, 依舊是 120px , 但 TALL 圖片(現稱 tall2x) 的高度變為 140px, 這顯然超過了原先的 linebox 的高度 120px. 在這裡我們觀察到:

整條 .myspan 文本行被拆成了 3 個顯示行, 它們對應著系統中的 3 個 linebox .

  • 第一個和第三個 linebox 內沒有圖片, 因此它們的 linebox height 依舊是 120px.
  • 第二個 linebox 中插入了超高的圖片(>120px), 結果必然會撐大了第二個 linebox 的高度.
  • 而且,tall2x 圖片的底部這回不是去對齊 linebox bottom, 而是去對齊父元素的 baseline, 這進一步撐大了 linebox.

結果是, 整個 linebox 高達 188px .

[2019-03-22] 未決問題: bottom short.png 有兩個像素高度的誤差, 原因未明.

-

【案例三,inline 元素雙重嵌套 (同時發現 Chrome Bug)】

[CASE 3.0] span_nested.html

<!doctype html>
<html>
<head>
<title>Figure 6-17</title>
<style type="text/css">
:root {
box-sizing: border-box;
}

*,
*::before,
*::after {
box-sizing: inherit;
}

body {
width: 500px;
margin: 0px;
}
p {
margin: 0px; /* if omit, margin-top will equal to font-size */
}
.myspan {
font-size: 24px;
line-height: 120px; /* same as line-height:5 */
border: 6px solid #8f8;
}
.feeder {
vertical-align: bottom;
}
.intexttop {
line-height: initial;
vertical-align: text-top;
border: 1px dashed blue;
}
.alignmark {
position: fixed;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
left: 0px;
width: 500px;
top: 120px;
height: 0px;
}
.alignmark2 {
top: 240px;
}
.nestblue {
line-height: 3; /* NOTE HERE */
color: blue;
border: 1px dashed blue;
vertical-align: baseline;
}
.nestshort {
line-height: initial;
vertical-align: baseline;
}
</style>
</head>
<body>

<p class="mypara">
<span class="myspan">This paragraph, as you can see quite clearly, contains
a <img class="feeder" src="tall.png" width="30" height="60" /> image and
a <span class="nestblue">(H3L)<img class="nestshort" src="short.png" />(H3R)</span> pic,
and then some text which is not tall.</span>
</p>

<div class="alignmark"></div>
<div class="alignmark alignmark2"></div>
</body>
</html>

這回用 Firefox 60 ESR 作為範本瀏覽器,顯示如下:

解讀:

  • 主體文字中嵌套了一個名曰 .nestblue 的 <span> 文本塊, 用藍色虛線框框起, 且其中的文字也用藍色.

  • .nestblue 的 line-height 故意被設成 3 (即 24px*3=72px). 裡頭的文字 H3L/H3R 即提示我們, 這塊藍色的東西, 其 line-height 是 3, L/R 表示 left/right .

  • .nestshort 是個 <img> 元素. 這樣就形成了嵌套關係:

    .myspan → .nestblue → .nestshort

  • .nestshort 的 vertical-align 初始值被設為 baseline .

接下來觀察的重點是: 我們調整 .nestshort 的 vertical-align 時, 它一定是跟直接父元素(.nestblue)的某個對齊點進行對齊嗎? 下面的三種情況揭示了答案。

結語

vertical-align 的全局觀已經形成,這個全局觀為我建立了一個理解 vertical-align 具體行為的框架,今後若遇到本文沒有提及的細節問題,我想應該都能夠在這個框架上找到一個契合點來進行解釋、或是進行合理的推測。在沒有文檔為我們闡述所有細節的情況下,有一套思想的框架特別有用。

祝好運。

END (初稿:2019.03.23)


推薦閱讀:

TAG:CSS |