一、表現明顯的斷背基情
衆所周知,
vertical-align
支援很多屬性值,足足可以組成一個足球隊了:
/* 關鍵字值 */
vertical-align: baseline;
vertical-align: sub;
vertical-align: super;
vertical-align: text-top;
vertical-align: text-bottom;
vertical-align: middle;
vertical-align: top;
vertical-align: bottom;
/* <長度> 值 */
vertical-align: 10em;
vertical-align: 4px;
/* <百分比> 值 */
vertical-align: 10%;
/* 全局值 */
vertical-align: inherit;
vertical-align: initial;
vertical-align: unset;
其中,有個屬性值暴露了
vertical-align
和
line-height
之間的基友關系,大家猜猜看是哪個屬性值?
哇塞,好厲害!居然被大家一眼就看出來了,沒錯,就是“百分比值”。
vertical-align
的百分比值不是相對于字型大小或者其他什麼屬性計算的,而是相對于
line-height
計算的。舉個簡單的例子,如下CSS代碼:
{
line-height: 30px;
vertical-align: -10%;
}
實際上,等同于:
{
line-height: 30px;
vertical-align: -3px; /* = 30px * -10% */
}
CSS屬性何其多,偏偏跟
line-height
有一腿,這不是有基情那是什麼?
//zxx: IE6/IE7浏覽器下的vertical-align的百分比值不支援小數line-height
二、背地裡無處不在的基友關系
//zxx: 注意,和
vertical-align
的地下基友關系從HTML5文檔聲明開始的,是以,以下探讨的現象,都是在頁面為HTML5聲明前提下,類似下面的doctype:
line-height
另外,下面很多效果直接就是真實示範,是以,請使用現代浏覽器觀摩下面的内容。如果發現某些行為與描述不比對,且浏覽器正常,那可能是因為你通路的并不是原出處。<!doctype html> <html>
① 基本現象
要八卦
vertical-align
和
line-height
之間的關系,我們不妨從一個極其簡單的現象入手。假設,我們有一個
<div>
标簽,然後,裡面有一張
<img>
圖檔,我們的HTML代碼就是這樣子:
<div><img src="mm1.jpg"></div>
然後,表現就是一張圖檔呈現,類似下面這樣:
恩,看上去很正常,一切都是理所當然。然而,如果我們給這個
<div>
元素增加一個背景色,例如淡藍色:
<div style="background-color:#e5edff;"><img src="mm1.jpg"></div>
則會是下面這樣:
會發現圖檔下面有一段空白空間:
想必大家都遇到過類似問題,不知大家有沒有思考過,為什麼圖檔下面有留有一段間隙呢?
實際上,這段空白間隙就是
vertical-align
和
line-height
攜手搞的鬼!
首先,大家一定要意識到這麼一點:對于内聯元素,vertical-align與line-height雖然看不見,但實際上「到處都是」!
是以,對于内聯元素各種想得通或者想不通的行為表現,基本上都可以用
vertical-align
和
line-height
來解釋,以及進行行為矯正,然而,要深入了解這些行為表現,還是需要狠花一番功夫的,是以,下面的内容,請確定你有半小時充足時間細細閱讀,别的地方可是看不到的。
② 幽靈空白節點
「幽靈空白節點」這個概念我自己命名的,注意,是我個人YY出來的,是我自己便于了解某些行為特征提出的概念。規範可能有類似的概念,但名稱并非這個。 W3C規範雖然有很多行為的解釋和說明,但是,畢竟官方的東西,要求嚴謹正式,但是,也會有太幹太澀的感覺。如果快速掌握和了解這些行為表現呢?就我個人而言,從兩方面入手:1.情感化認知;2. 具象化思維。
例如,我稱
vertical-align
和
line-height
為好基友(包括以前稱浮動和絕對定位是兄弟),就是“情感化認知”;而這裡的「幽靈空白節點」就是“具象化思維”。
那「幽靈空白節點」是個什麼意思呢?
在HTML5文檔聲明下,塊狀元素内部的内聯元素的行為表現,就好像塊狀元素内部還有一個(更有可能兩個-前後)看不見摸不着沒有寬度沒有實體的空白節點,這個假想又似乎存在的空白節點,我稱之為“幽靈空白節點”。 //zxx: 自己搗騰的概念,不是權威,歡迎其他小夥伴回報權威解釋
抽象了這個概念,絕對定位與
text-align
的一些行為表現,以及這裡的行為表現,就好了解了。
還是上面的圖檔下邊緣留白隙的例子,實際上,這種行為表現,就跟圖檔前面或者後面有一個寬度為0的空格元素表現是一緻的。但是,空格是透明的,為了便于大家了解,我就直接使用很明顯的匿名inline box, 也就是字元代替。如下,大家會發現,圖檔下面的間隙,依舊是那個間隙。
zxx
下面要解釋這個間隙就好解釋了。下面,我們讓新增的文本inline-block化,然後弄個白色背景,顯示其占據的高度。
zxx
會發現,圖檔下面的間隙,依舊是那個間隙。但是,我們的了解就好了解了。回答下面幾個問題,我們就知道表現的原因了:
-
預設的對齊方式是?vertical-align
- 後面zxx文字的高度從何而來?
上面2個問題就很簡單了:
-
預設值是vertical-align
, 也就是基線對齊。而基線是什麼,基線就是字母X的下邊緣(參見“字母’x’在CSS世界中的角色和故事”一文)。是以,妹子圖檔的下邊緣就和後面zxx中的字母baseline
下邊緣對齊(見下圖)。而字元x
本身是有高度的,對吧,于是,圖檔下面就留白了。zxx
- 而
文字的高度是由行高決定的。zxx
是以,簡單的圖檔下面留白行為表現,本質上,就是
vertical-align
和
line-height
背地裡搞基造成的。
知道了問題的原因,我們就可以對症下藥,準确搞定圖檔下面我們不希望看到的間隙。怎麼搞呢?一對基友,
vertical-align
和
line-height
我們随便搞定一個就可以了。
比方說
vertical-align
.
1. 讓vertical-align失效
圖檔預設是
inline
水準的,而
vertical-align
對塊狀水準的元素無感。是以,我們隻要讓圖檔
display
水準為
block
就可以了,我們可以直接設定
display
或者浮動、絕對定位等(如果布局允許)。例如:
img { display: block; }
則妹子就會變這樣:
下面的空隙不見了。
2. 使用其他vertical-align值
告别
baseline
, 取用其他屬性值,比方說
bottom
/
middle
/
top
都是可以的。
vertical-align:bottom vertical-align:middle vertical-align:top
zxx
3. 直接修改line-height值
下面的空隙高度,實際上是文字計算後的行高值和字母x下邊緣的距離。是以,隻要行高足夠小,實際文字占據的高度的底部就會在x的上面,下面沒有了高度區域支撐,自然,圖檔就會有容器底邊貼合在一起了。比方說,我們設定行高5像素:
div { line-height: 5px; }
zxx
4. line-height為相對機關,font-size間接控制
如果
line-height
是相對機關,例如
line-height:1.6
或者
line-height:160%
之類,也可以使用
font-size
間接控制,比方說來個狠的,
font-size
設為大雞蛋
, 本質上還是改變
line-height
值.
div { font-size: 0; }
zxx
③ 基本現象衍生:垂直居中
由于「幽靈空白節點」的存在,是以,我們可以進一步衍生,實作其他更實用的效果,比方說任意尺寸的圖檔(或者内聯塊狀化的多行文字)的垂直居中效果。就是借助本文的兩位男主角,
vertical-align
和
line-height
。
你想啊,圖檔後面(前面)有個類似空格字元的節點,然後就能響應
line-height
形成高度,此時,圖檔再來個
vertical-align:middle
,當當當當,就可以和這個被行高撐高的「幽靈空白節點」(近似)垂直對齊了。
例如:
div { line-height: 240px; }
img { vertical-align: middle; }
然後就會這樣子:
不過上面的效果并不是完全的垂直居中,隻是近似(稍微仔細看可以看出來)。為什麼隻是近似呢?那是因為「幽靈空白節點」高度行高撐開,其垂直中心是字元content area的中心,而對于字元
x
而言,都是比絕對中心位置要下沉的(不同字型下沉幅度不一樣),換句更易懂的描述就是
x
的中心位置都是在字元内容區域高度中心點的下方,而這上下的偏差就是這裡圖檔上下間距的偏差。
我特意把字元
x
使用大字号示範了下:
換句更簡單的話說就是:middle中線位置(字元
x
的中心)并不是字元内容的絕對居中位置。兩個位置的偏差就是圖檔近似居中的偏差。
嘛嘛,單純的文字還是太蒼白了,截個圖示意下吧:
是以,要想完全垂直居中,最先想到的方法就是讓後面的“幽靈字元”也是
vertical-align:middle
,然而,呵呵,既然稱之為“幽靈”就表示不會受非繼承特性的屬性影響,是以,根本沒法設定
vertical-align:middle
,除非你自己建立一個顯示的内聯元素。
我們就沒有辦法了嗎?當然不是,“幽靈字元”可以受具有繼承特性的CSS屬性影響,于是,我們可以通過其他東西來做調整,讓字元的中線和字元内容中心線在一起,或者說在一個位置上就可以了。有人可能要疑問了,這能行嗎?啊,是可以的。
怎麼搞?很簡單,
font-size:0
, 是以此時content area高度是0,各種亂七八糟的線都在高度為0的這條線上,絕對中心線和中線重合。自然全垂直居中:
div { line-height: 240px; font-size: 0; }
img { vertical-align: middle; }
結果是:
處女座的你,是不是看過去舒服多啦!?
這種通過
line-height
定高,元素
vertical-align:middle
垂直居中的方法不僅适用于現代浏覽器,連IE7浏覽器也是支援的:
不過和其他浏覽器再使用上還是有些需要注意的地方,就是,HTML不能這樣:
<div><img src="mm1.jpg"></div>
而是需要在圖檔标簽結束處留下空格後者換行:
<div><img src="mm1.jpg"><!-- 這裡要折行或空格 -->
</div>
④ 複雜現象
多年前曾分享過“text-align:justify下清單的兩端對齊布局”的技術,其中,為了讓任意個數的清單最後一行也是對齊排列,在清單最後會輔助清單等寬的空标簽元素來占位,類似下面紅色高亮HTML代碼:
.justify-fix { display: inline-block; width: 128px; }
<div style="text-align: justify;">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<i class="justify-fix"></i>
<i class="justify-fix"></i>
<i class="justify-fix"></i>
</div>
為了節約空間,我就使用小圖示意:
同樣的,在白色背景下,似乎看上去效果還不賴,但是,如果給
div
容器加個背景色~~
會驚訝的發現,下面多了很大一塊間隙(如下截圖):
為了便于大家看其究竟,我把占位
i
元素
outline
高亮下,于是,效果如下:
結果會發現,上面巨大的空隙是由占位
i
元素上面和下面的間隙共同組成的。
下面問題來了:上面的間隙是如何産生的?下面的間隙是如何産生的?如果去除這些間隙呢?
很多時候,複雜問題是由簡單問題組合而成的,實際上,這裡的間隙現象的始作俑者和上面的簡單現象一樣,都是
vertical-align
和
line-height
搞基帶來的不好的影響。
按照之前問題解決方法,我們可以直接來個
line-height:0
解決垂直間隙問題:
div { line-height: 0; }
結果圖檔和圖檔之間的間隙是沒有了,但是,圖檔和最後的占位元素之間依然有個幾像素的間距,
,啊啊啊啊,這究竟是什麼鬼?
簡單現象的背後往往有大的學問,接下來是本文的高潮了,究其原因,要說到inline-block元素和基線baseline之間的一些糾纏的關系。
⑤ inline-block和baseline
CSS2的可視化格式模型文檔中有一麼一段話:
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裡面既沒有line boxes或者本身’overflow’屬性的計算值而不是’visible’, 這種情況下基線是margin底邊緣。
這段文檔中出現了很多專有名詞
line box
,
line boxes
等,這些是内聯盒子模型中的概念,是CSS進階必備知識。我在“浮動深入了解(一)”一文的中間穿插介紹了該模型。//zxx: 我現在後悔了,内聯盒子模型當初應該直接獨立成一篇文章,這樣其他文章可以很幹淨地引用,所謂文章的子產品化書寫
如果大家沒有足夠精力去學習之,可以先看下面這張圖:
由于上面的譯文是直譯的,了解起來還是有些拗口,我使用通俗的話描述就是:一個inline-block元素,如果裡面沒有inline内聯元素,或者overflow不是visible,則該元素的基線就是其margin底邊緣,否則,其基線就是元素裡面最後一行内聯元素的基線。
納尼,還是沒反應過來?
那我們看下面這個例子,應該就知道什麼意思了。
兩個同尺寸的
inline-block
水準元素,唯一差別就是一個空的,一個裡面有字元,代碼如下:
.dib-baseline {
display: inline-block; width: 150px; height: 150px;
border: 1px solid #cad5eb; background-color: #f0f3f9;
}
<span class="dib-baseline"></span>
<span class="dib-baseline">x-baseline</span>
結果,科科:
x-baseline
會發現,明明尺寸、display水準都是一樣的,結果呢,兩個卻不在一個水準線上對齊,為什麼呢?哈哈,上面的規範已經說明了一切。第一個框框裡面沒有内聯元素,是以,基線就是容器的margin下邊緣,也就是下邊框下面的位置;而第二個框框裡面有字元,純正的内聯元素,是以,第二個框框就是這些字元的基線,也就是字母x的下邊緣了。于是,我們就看到了框框1下邊緣和框框2裡面字元
x
底邊對齊的好戲。框框2有個小彩蛋,點選可以toggle其
innerHTML
,會發現,如果框框2裡面沒文字,就和框框1舉案齊眉了。
下面我們要做一件很有必要的事情,用來幫助我們了解上面複雜例子在
line-height
值為
後的表現,什麼事情呢?哈,同境界模拟,我們也設定框框2的
line-height
值為
,于是,就會是下面這樣的表現:
x-baseline
知道框框2為何又下沉了一點嗎?
因為字元實際占據的高度是由行高決定的,當行高變成0的時候,字元占據的高度也是
,此時,高度的起始位置就變成了字元content area的垂直中心位置,于是,文字就一半落在看看2的外面了。
由于文字字元上移了,自然基線位置(字母
x
的底邊緣)也往上移動了,于是,兩個框框的垂直落差就更大了。
OK,明白了上面的簡單例子,也就能明白上面的複雜例子。緊接着,如果我們在最後一個占位的
<i>
元素後面新增同樣的
x-baseline
字元,則:
x-baseline
大家是不是就可以明白原因所在啦!
額~居然還有小夥伴皺眉頭,那我再用文字解釋下:
現在行高
line-height
是
, 則最後的
x-baseline
的垂直中線就和上面一列的圖檔對齊,而基線呢,就在中線下面差不多半個x的高度地方,而這個高度落差就是最後圖檔和容器的間隙高度值,因為前面的
<i class="justify-fix">
是個空元素,基線是自身的底部,哈哈,造業啊!
OK,一旦知道了現象的本質,我們就能輕松對症下藥了!要麼改造占位
<i>
元素的基線、要麼改造“幽靈空白節點”的基線位置、要麼使用其他
vertical-align
對齊方式~
首先,來個最有意思的方法,對吧,改造占位
<i>
元素的基線。這個很簡單,對吧,隻要在空的
<i>
元素裡面随便放幾個字元就可以了,例如,裡面有個
x
:
xx-baseline
會發現,間隙沒有了!
為什麼呢?哈哈,因為
<i>
元素的基線和“幽靈空白節點”的基線位置現在一緻了,沒有了錯位,自然就不會有間隙啦!
改造“幽靈空白節點”的基線位置,哈哈,使用
font-size
,字型足夠小時,基線和中線會重合在一起,什麼時候字型足夠小呢,就是
. 于是,CSS代碼(
line-height
如果是相對值,
line-height:0
也可以省掉):
div { font-size: 0; }
使用其他
vertical-align
對齊方式,就是讓兩端對齊的清單元素
vertical-align:top/bottom/...
之類。
div { line-height: 0; }
.justify-fix { display: inline-block; width: 128px; vertical-align: top; }
最後的效果是:
恩恩,各種方法都完美解決了垂直間隙的問題,來,各個大大的贊!
三、基友關系暴露之後
至此,
vertical-align
和
line-height
的斷背基友關系算是徹底暴露了,而且,從行為表現上來看,
line-height
是攻,
vertical-align
是個受。而很多内聯元素的行為表現,就是這對基友搞七搞八一起搞出來的。
以前,關系處于地下的時候,我們可能不會明白,為何男廁所的卷紙用得比女廁所還快;但是,現在關系暴露了,很多以前我們想不明白的事情一下子就豁然開朗了。
是以,我們要以正确地心态去看待這對好基友,畢竟,他們可以CSS屆非常重要的兩個主力大将。
本文牽扯的知識點甚多,建議大家如果想在重構領域有所造詣,很多基本的卻很深入的東西是很有必要弄透的。篇幅有限,有不少知識點都是一筆帶過的,大家若有疑問,可以自己去檢索與研究,例如,
vertical-align
各個值的規範解釋,内聯盒子模型,等等。也歡迎各種方式交流。
本文為原創文章,包含腳本行為和樣式控制,會經常更新知識點以及修正一些錯誤,是以轉載請保留原出處,友善溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本文位址:http://www.zhangxinxu.com/wordpress/?p=4925