帶你深入剖析inline-block屬性值的前世今生

來源:互聯網
上載者:User

標籤:

曾幾何時,display:inline-block 已經深入「大街小巷」,隨處可見 「display:inline-block; *display:inline; *zoom:1; 」這樣的代碼。如今現代瀏覽器已經全面支援這個屬性值了,上面的代碼只是為了相容 IE6、7 而已。那麼你真的瞭解 inline-block 了嗎?本文將帶你深入剖析該屬性值的前世今生,讓你更好的理解和運用 inline-block。(本文約定 display:inline-block 簡寫為 inline-block)

開篇我們來看幾個問題:

IE6、7 真的不支援 display:inline-block 嗎?display:inline-block 後的元素為什麼會產生水平空隙,這真的是 bug 嗎?如何更好的解決 display:inline-block 元素間產生的水平空隙?一、inline-block 前世1.認知

也許有人問你為何要寫「 display:inline-block; *display:inline; *zoom:1; 」 來相容 IE6、7 時,你會立馬答道:因為 IE6、7 不支援 display:inline-block 唄!不知道何時起,慣性思維給開發人員帶來了這樣一個可怕的概念。萬物都是辯證的,當你寫下這些的時候,可曾懷疑過福士觀點真的可靠嗎?也許你認為這些無關 緊要,實現效果就好。但是如果不能理解每個屬性或屬性值的根本,你將永遠無法全面的瞭解它,人云亦云只會讓你淺嘗輒止,止步不前。那麼這裡就涉及到所謂的 「CSS 學習瓶頸」的問題了,這個問題張鑫旭《說說CSS 學習中的瓶頸》一文有詳細闡述,雖然部分觀點我不是很贊同,但是中心思想還是很值得思考的。文中有幾個不錯的問題這裡也列舉出來供大家觀摩:

      line-height:150% 和 line-height:1.5 的區別是?float 為何會讓外部容器高度塌陷?這是 bug?(我的答案在《

我們為何要清除浮動

    》)vertical-align 的表現為何在IE7, IE8, IE9 下表現不盡相同?其中的渲染機制是?

好了,回到 inline-block 的認知的問題,我的觀點是:

IE 從 5.5 開始就已經支援 display:inline-block 了,只是支援的並不是那麼完善。

在 msdn 微軟開發人員社區,找到了 IE 從5.5 開始支援 inline-block 的證據:

The inline-block value is supported starting with Internet Explorer 5.5. You can use this value to give an object a layout without specifying the object’s height or width.

這裡明確指出:從 IE5.5 開始支援 inline-block。

連結:http://msdn.microsoft.com/zh-cn/library/ie/ms530751(v=vs.85).aspx

那麼既然 IE5.5 開始就已經支援了 inline-block,為何我們還要寫那麼一坨 CSS 呢?同時我們知道 IE6、7 中 display:inline-block 是可以觸發 hasLayout 的,觸發了 hasLayout的元素表現出來的特徵就是一個獨立的矩形容器,可以設定寬高而且不受外部元素的影響,類似於現代瀏覽器中的 Block formatting contexts (塊級格式化上下文)的概念。

下面來做一個詳細的測試,分別看看 IE6 中 inline 元素和 block 元素的表現:

1)inline 元素 display:inline-block

IE6 中如下:



複製代碼代碼如下:
.dib-inline, .dib-block {
width:100px;
height:30px;
line-height:30px;
text-align:center;
}
.dib-inline {
display:inline-block;
}


測試表明:IE6 中 inline 元素只要觸發了 hasLayout 其表現就類似於 inline-block,這裡設定 display:inline-block; 或者 zoom:1; 等其他屬性值可以觸發 hasLayout ,表現出來是一樣的。

 

2)block 元素 display:inline-block

IE6 中如下:



複製代碼代碼如下:
.dib-inline, .dib-block {
width:100px;
height:30px;
line-height:30px;
text-align:center;
}
.dib-block{
display:inline-block;
}


測試表明:IE6 中 block 元素即使觸發了 hasLayout 也不能具有 inline-block 元素不換行的特性。想要 block 元素支援 inline-block 元素的特性,我們可以這樣做:

複製代碼代碼如下:
.dib-block {
display:inline;
zoom:1;
}


首先讓 block 元素轉化為 inline 元素,強制其不換行;然後通過 zoom:1 觸發hasLayout,使其可以設定寬高。修複後的 如下:

 

3)結合現代瀏覽器

綜上,現代瀏覽器都支援 display:inline-block ,IE6、7 inline 元素也可以達到同樣的效果,IE6、7 block 元素需要設定 display:inline; zoom:1; 它們結合在一起便是:

複製代碼代碼如下:
display:inline-block; /* 現代瀏覽器 +IE6、7 inline 元素 */
*display:inline; /* IE6、7 block 元素 */
*zoom:1;


為了不讓支援CSS2.1 inline-block 的瀏覽器 重設為 inline,我們針對 IE6、7 做一個 hack。由於現代瀏覽器也開始支援 zoom 屬性,這裡只是希望 IE6、7 中生效,所以還是 hack 一下比較合適。至此產生了我們熟悉的相容各個瀏覽器的 inline-block 寫法。

 

小結:IE6、7 並不是不支援 inline-block,只是 block 元素需要做一些處理來達到 inline-block 的效果。

2. 到底什麼是 inline-block

說了很多,或許很多朋友還不是太明白到底什麼是 inline-block?W3C 在 CSS2.1 The ‘display’ property 中描述如下:

This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

大致意思就是:inline-block 後的元素建立了一個行級的塊容器,該元素內部(內容)被格式化成一個塊元素,同時元素本身則被格式化成一個行內元素。

直白一點的意思就是:inline-block 的元素既具有 block 元素可以設定寬高的特性,同時又具有 inline 元素預設不換行的特性。當然不僅僅是這些特性,比如 inline-block 元素也可以設定 vertical-align 屬性。簡而言之:

inline-block 後的元素就是一個格式化為行內元素的塊容器( Block container )

怎麼樣?聽起來還不錯吧!

3. inline-block 緣從何起?

前面已經證明了 IE 5.5 開始就支援了 inline-block,那麼 IE5.5 是什麼時候發布的呢?話說當年網景與 IE 大戰,IE5.5 那是何等的風騷……(好吧,此處略去十頁)。從維基百科的資料來看,IE5.5 beta1 的發布時間是:1999年12月,最終版本是 2000年7月。那麼 W3C 標準中是何時才出現 inline-block 這個值的呢?

在 CSS1 規範中,「display」的值僅包括: block | inline | list-item | none 。CSS2.1中才添加了 inline-block 屬性值。一絲繼續舔著手指,用那苦逼的英語水平終於翻到了這份草案:http://www.w3.org/TR/2002/WD-CSS21-20020802/visuren.html#display-prop, 這份草案的日期是 2002年8月2日,納尼!!!原來我們糾結了半天的 inline-block , IE5.5 至少提前兩年就提出來了啊!難道是微軟給 W3C 提議後,CSS 2.1才加入的?(不過我看到 W3C 官網有一個關於是否增加 inline-block 的投票)好吧這個問題也許有一天 IE 某個開發人員寫《 IE回憶錄》的時候我們才能瞭解到其中的內幕。如果找到更早關於 inline-block 的 CSS草案,也麻煩告知一絲一聲。好吧,如果你還不相信,打微軟官方電話問問吧 800-820-3800(不是 DHC 哦!)。

原來我們一直討論的 inline-block 在 IE 6、7中和 CSS2.1 中的(現代瀏覽器所支援的) inline-block 上壓根不是一個東東嘛,IE6、7 中的 inline-block 更像是 IE 的私人屬性值,他們本身就不具有可比性。簡單、絕對的認為 IE6、7 不支援 inline-block 好比一葉障目,看到前面,卻看不到後面,太過於片面。誠然,IE6、7 的 hasLayout 給我們帶來了很多麻煩,但是不得不承認微軟的 IE 在網頁多語言文本混排上的先進性,尤其是 CJK 文字和西文的混排,超越其他瀏覽器至少5年。

總結:

IE5.5 後開始支援 inline-block, 但是它所支援的 inline-block 不能等同於 CSS2.1 中的 inline-block,因為 IE5.5 比 CSS2.1 更早提出 inline-block 的概念並作為所謂的「私人屬性值」使用,所以二者表現出來的效果是不完全一致。IE 5.5、6、7 、8(Q)中 block 元素對 inline-block 支援不完整,如果要達到類似的效果,需要先設定為 display:inline,然後使用 zoom:1 等觸發hasLayout。IE 5.5、6、7 、8(Q)中 inline 元素欲達到 inline-block 的效果只需直接設定此屬性值或使用 zoom:1 等均可。

《各瀏覽器對 ‘display’ 特性值的支援程度不同》

二、inline-block 今生1. display:inline-block 後的元素為什麼會產生水平空隙,這真的是 bug 嗎?

這麼一個神奇的屬性,為何大家一直避而遠之呢?這恐怕還得從 inline-block 元素之間產生的水平空隙(間隙)說起吧。

現代瀏覽器中 inline 和 block 元素 display:inline-block 後均會產生水平空隙;

IE6、7,IE8(Q)類比 display:inline-block 後分兩種情況:

IE6、7,IE8(Q)中:inline 元素會產生空隙,block 元素不會產生空隙。

看看 inline 元素預設的表現情況如何?原來預設就有空隙存在!它們是誰?是空白符(white space)!

W3C 9.1 White space 中規定以下元素屬於空白符(white space):

ASCII 空格 ( )ASCII 定位字元 (	)ASCII 換頁符 ()零寬度空格 (​)「這個在閉合浮動中也有運用到」

9.3.2 Controlling line breaks 中進一步闡述:

A line break is defined to be a carriage return (
), a line feed (
), or a carriage return/line feed pair. All line breaks constitutewhite space.

For more information about SGML’s specification of line breaks, please consult the notes on line breaks in the appendix.

折行被定義為一個斷行符號符(
),一個分行符號 line feed (
),或者一個斷行符號、換行的組合。所有的折行構成了空白符。

有關 SGML 規範中折行的更多資訊,請參閱附錄中關於折行的注釋。

通常情況下,對於多個連續的空白符(空格,分行符號,斷行符號符等),瀏覽器會將他們合并為一個空白符。CSS 中由 white-space 這個屬性來控制:

white-space:normal | pre | nowrap | pre-wrap | pre-line

預設值:normal

normal:預設處理方式。pre:用等寬字型顯示預先格式化的文本,不合并文字間的空白距離,當文字超出邊界時不換行。可查閱 pre 對象nowrap:強制在同一行內顯示所有文本,直到文本結束或者遭遇 br 對象。pre-wrap:用等寬字型顯示預先格式化的文本,不合并文字間的空白距離,當文字碰到邊界時發生換行。pre-line:保持文本的換行,不保留文字間的空白距離,當文字碰到邊界時發生換行。

註:IE7及更早瀏覽器不支援 CSS2.1 新增的 pre-wrap | pre-line。

所以這並不是 inline-block 後產生的 bug,而是因為 inline-block 具有 inline 元素固有的特性。那麼為何 IE6、7 block 元素沒有產生空隙呢?其實前面也提到了 IE 的hasLayout,具有獨立性,所以產生 hasLayout 的元素之間表現出來互不影響,這也再次表明 IE6、7 中的 inline-block 不能等同於 CSS2.1 中的 inline-block。如果非要說是有 bug, IE6、7 block 元素 inline-block 後不產生空隙才是 bug。

測試表明刪除分行符號後,inline 元素間的空隙就「消失」了:

2.去掉 inline-block 產生的空隙

為了讓各個瀏覽器表現一致,更好的還原視覺設計搞,很多時候我們需要去掉 inline-block 產生的空隙。

上一節中我們已經知道產生空隙的根本性原因是:

HTML 中的分行符號、空格符、定位字元等產生了空白符,而這些歸根結底都是字元,那麼它們的大小都是 受 font-size 來控制的,字型大小直接導致 inline 或者 inline-block 後元素之間空隙的大小,把 inline-block 元素間的空隙認為總是某個固定大小是錯誤的。

用 GIF 動畫的形式來表明對應關係:

很清楚的看到,當 font-size:0 的時候元素間的空隙都為0了,或許到這裡你會感到很欣喜了,原來掌握的根本性原因這麼簡單就搞定了啊!

然,理想是豐滿的,現實是骨感的。

大部分瀏覽器是支援 font-size:0 的。很明顯,我們要和 IE 6、7 這兩個妖孽進行一番戰鬥。

font-size:0 的支援情況

1)Chrome

低版本的 chrome 瀏覽器為了不讓文字過小不利於閱讀,預設是不支援 font-size:0 的,還好我們有 -webkit-text-size-adjust 這個私人屬性來控制,當設為 none 時就支援字型大小為 0 了。我已經記不清楚 chrome 從哪個版本開始支援 font-size:0 了,反正我用 chrome 19 是支援了(有知道的朋友,煩請告訴一絲一聲,最好有官方更新說明)。但是,-webkit-text-size-adjust:none; 會直接導致頁面文字無法縮放,這對於使用者來說顯然是不友好的。所以-webkit-text-size-adjust:none; 一定要慎用,確保使用的地方沒有大面積的文字。

-webkit-text-size-adjust:none 的使用情境執行個體參閱:http://vip.etao.com/

2)Safari

Safari 5 依舊不支援 font-size:0 ,不過相信這些瀏覽器廠商都意識到了這個問題,在 Mac 平台最新的 Safari 6 已經很好的支援 font-size:0 了。

3)Firefox,Opera

經測試,Firefox12,Opera 10 ,這次表現不錯,支援 font-size:0 。

4)IE

IE8 以上支援 font-size:0;IE6、7 inline 元素 inline-block 後設定 font-size:0 始終有 1px 的空隙。

是不是一下子又開始頭疼了?沒關係,讓我們請出 letter-spacing 和 word-spacing 二位大神。既然空白符也是字元,那麼二位大神肯定是可以搞定它們的。

letter-spacing : normal | length (檢索或設定對象中的文字之間的間隔)word-spacing : normal | length(檢索或設定對象中的單詞之間插入的空隔)

normal: 預設間隔
length: 用長度值指定間隔,允許為負值。

還等什麼,我們趕緊試試吧:

第一步:使用 font-size:0經測試發現,chrome、firefox、IE8+、opera,inline 或 block 元素都沒有空隙了;
Safari 5.1.7 由於不支援 font-size:0 ,仍然存在空隙;


IE6、7、8(Q),inline 元素 inline-block 後始終存在 1px 左右的空隙。
第二步:處理 Safari 不支援 font-size:0 的問題上面已經指出 letter-spacing 是支援負值的,那麼這個負值到底取多少合適呢?經過測試得出的結論是:inline-block 產生的空隙與父級元素繼承或者設定的 font-family、font-size 有關,通常情況下,12px 大小的 tahoma 字型,inline-block 後元素間產生的空隙(間隙)大約是 5px;
各個字型詳細情況請參閱《inline-block空隙–letter-spacing與字型大小/字型關係資料表》。Firefox 中 letter-spacing 負值的絕對值大於空隙大小後,會導致元素整體位置向右位移;
Safari 中 letter-spacing 負值的絕對值大於空隙大小後,內部會發生重疊。

第三步:修複 IE6、7 中始終存在的 1px 空隙
既然 letter-spacing 已經無能為力了,那就試試 word-spacing 吧,直接設定 word-spacing:-1px。這裡需要注意的是,letter-spacing 和 word-spacing 同時使用可能導致衝突,所以我們需要在 IE6、7 中 hack 掉 letter-spacing。最終代碼如下:

複製代碼代碼如下:
font-size:0;/* 所有瀏覽器 */
letter-spacing:-5px;/* Safari 等不支援字型大小為 0 的瀏覽器 */
*letter-spacing:normal;
word-spacing:-1px;/* IE6、7 */


第四步:子項目重設回正常值
上述所有操作都是在父元素設定的,那麼子項目都會繼承這些屬性,字型大小為0了,子項目就什麼都看不到了,這並不是我們想要的。 同時字元和單詞間距我們也要把它重設為預設值。「font-size: 12px; letter-spacing: normal; word-spacing: normal;」最後:inline-block 更好的複用
或許你會擔心每次我都要去看字型和空隙之間大小的關係嗎?其實不然,通常情況下,全域字型都已經在 body 中指定了,根據全域字型設定合適的 letter-spacing 負值即可。如此一來,我們便可以放心大膽的使用 inline-block 了,結合 OOCSS 的思想,可以抽離出兩個複用的類,在需要設定 inline-block 元素的父級元素上定義一個「.dib-wrap」,該元素自身定義為「.dib」。這裡還有一個問題需要注意的是:由於 inline-block 具有 inline 元素的特性,在垂直方向上很多時候我們並不希望元素以「vertical-align:baseline」方式來呈現,所以在「.dib-wrap」中統一重設為「vertical-align:top」即可。3. 去除 inline-block 空隙終極解決方案(2012年8月17日更新)

複製代碼代碼如下:
.dib-wrap {
font-size:0;/* 所有瀏覽器 */
*word-spacing:-1px;/* IE6、7 */
}
.dib-wrap .dib{
font-size: 12px;
letter-spacing: normal;
word-spacing: normal;
vertical-align:top;
}
@media screen and (-webkit-min-device-pixel-ratio:0){
/* firefox 中 letter-spacing 會導致脫離普通流的元素水平位移 */
.dib-wrap{
letter-spacing:-5px;/* Safari 等不支援字型大小為 0 的瀏覽器, N 根據父級字型調節*/
}
}
.dib {
display: inline-block;
*display:inline;
*zoom:1;
}


其實在 YUI 3 中也全面運用了 inline-block 作為基礎布局,YUI 3 是這樣解決的:

複製代碼代碼如下:
.yui3-g {
letter-spacing: -0.31em; /* webkit: collapse white-space between units */
*letter-spacing: normal; /* reset IE < 8 */
word-spacing: -0.43em; /* IE < 8 && gecko: collapse white-space between units */
}
.yui3-u {
display: inline-block;
zoom: 1; *display: inline; /* IE < 8: fake inline-block */
letter-spacing: normal;
word-spacing: normal;
vertical-align: top;
}


顯然,這裡純粹使用了 letter-spacing 和 word-spacing 來控制元素間的空隙,局限性極大,-0.31em 和 -0.43em 只是因為 YUI 3 全域 cssfonts.css 裡設定是:「body { font:13px/1.231 arial,helvetica,clean,sans-serif; }」。

當然,如果你堅持使用把 html 寫在一行的方式來達到去除 inline-block 空隙的目的,我只能說:一切以犧牲結構來相容表現的行為都是耍流氓!所以探討此種方式去除空隙也將是無意義的,不在本文和作者考慮範圍之內。

4. 結局——本文產生的一些觀點如下:IE5.5 後開始支援 inline-block, 比 CSS2.1 更早提出 inline-block 的概念並作為所謂的「私人屬性值」使用。但是它所支援的 inline-block 不能等同於 CSS2.1 中的 inline-block,IE 5.5、6、7 、8(Q)中 block 元素對 inline-block 支援不完整,因此二者表現出來的效果是不完全一致。
產生 inline-block 空隙的根本性原因是:HTML 中的分行符號、空格符、定位字元等合并為空白符,字型大小不為 0 的情況下,空白符自然佔據一定的寬度,因此產生了元素間的空隙。
慎用 -webkit-text-size-adjust:none,它將會導致頁面無法通過縮放來改變字型大小。

三、inline-block 未來

如今,Mac 平台下的 Safari 6 已經支援 font-size:0 了,相信很快 Windows 平台的 Safari 如果發布 5.X 的更新,也會支援字型為 font-size:0 了。等到 IE6、7 滅亡之後,世界就真真兒的美妙了!最後說一點:inline-block 與 float 也是無法直接比較的,請不要再討論 inline-block 和 float 哪個更好的話題了。inline-block 從 IE5.5 一路走來,存在即是合理,以後有時間在總結一下 inline-block 與 float 的使用情境的區別。

在不改變 CSS 定位機制的前提下,inline-block 應該是首選,而不是以「奇淫技巧」存在的。有感打油詩一首:

網事如煙
CSS 紅塵裡
inline-block 知多少
你在這頭
inline-block 在那頭
用與不用
它就在那裡
不悲不喜

PS:

    為了更好的排版,本文使用繁體中文引號 「」代替簡體中文小蝌蚪引號;中英文混排的時候英文首尾各加一個空格;以後文章有需要的時候也都將使用 gif 動畫配合說明。

測試環境 作業系統版本: Windows 7 企業版 6.1(組建 7600) 瀏覽器版本:IE6
IE9
Firefox 14.0.1
Chrome 19.0.1084.46
Safari 5.1.7(7534.57.2)
Opera 12.50 最後更新時間: 2012-8-22

帶你深入剖析inline-block屬性值的前世今生

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.