margin系列之bug巡演(三)

doyoe發表於2013-12-24

原文地址:margin系列之bug巡演(三) by @doyoe

IE8按鈕margin auto居中失效Bug

你會猛然覺得,這是正解啊,因為 button 或者 input type button型別 的元素是 inline-level 的。

不對啊,button 應該是 inline 的吧?哦,可能是 inline-block

在這之前,我們似乎要先明確一些基礎知識。

什麼是 inline-level 元素?

要知道 inline-level 元素並不等於 inline 元素,也就是說 行內級元素行內元素 是兩個不同的概念。

inline-level 元素包含 display 值為:

  • inline
  • inline-block
  • inline-table
  • inline-flex
  • other inline-*

以上情況時,元素可被稱之為 inline-level 元素,但不都是 inline 元素。

什麼是 block-level 元素?

block-level 指的是 display 值為 block 的元素嗎?我知道不少人一直有這樣的認知,不過這不完全準確。

block-level 元素包含 display 值為:

  • block
  • list-item
  • table
  • table-*
  • flex
  • 如果position既不是static也不是relative、float不是none或者元素是根元素,當display:inline-table時,display的計算值為table;當display值為 inline | inline-block | run-in | table-* 時,display的計算值為block

有如上情況時的元素均被稱之為 block-lavel 元素。同時 block-levelblock 也不是同一個概念,所以如果你認為 display 值為 list-item 的 li 不是 塊級元素,那就錯了。

看到這裡,你對 塊級元素塊元素行內級元素行內元素 這個4個概念,應該已經有了比較清晰的瞭解?

margin keyword auto只能應用在常規流中的 block-level 元素上

  • 當一個塊級元素定義了 position 值為非 staticrelative 之外的值時,margin-right/left auto 的計算值為0;
  • 當一個塊級元素定義了 float 值為非 none 之外的值時,margin-right/left auto 的計算值為0;
  • 非塊級元素的margin-right/left auto 的計算值為0;

計算值為0,即說明其應用使用值的意圖失敗。所以在有如上情形的場景中,都無法使用 auto 來實現水平居中。同時也說明了,只有 normal flowblock-level 才能應用 margin keyword auto。

margin可以應用於所有元素嗎?

這顯然不行。準確的說:margin可以應用在除某些table-*元素和某些行內元素之外的所有元素上。

和margin親近的table-*系元素

  • table
  • inline-table
  • table-caption

除了 display 值為以上3種之外的 table系 元素,都不能應用 margin ,比如:th, td。

和margin親近的 inline-level 元素

我之前面試的時候常會問候選人,行內元素不能設定寬高對嗎?大部分人會告訴我說是;然後我又會問,那為什麼 img 元素可以設定寬高呢?有人會告訴我,因為 img 是個特殊的元素?接著我又會問題,img 是如何特殊的?然後,然後就沒然後了,因為沒聲音了。

恩,img 確實是個特殊的元素。它特殊在哪裡?它的特殊就在於它是一個行內建換元素。

所有的置換元素都可以設定 margin 屬性,並且可以設定寬高,這就是為什麼 img 是行內元素卻可以設定 widthheight

什麼是置換元素(Replaced elements)?

一個元素擁有內在的二維屬性,其寬高屬性受外部資源影響,預設擁有CSS格式,這樣的元素被稱為置換元素。

意思就是說置換元素的寬高不完全由CSS決定,還受其自身內容和外部資源所影響。

舉個例子來說,仍然說 img 元素吧,你會發現,如果你 src 進來不同尺寸的資源,那麼在 viewport 上顯示的圖片寬高也是不同的,也就是說 img 元素的寬高會受外部資源影響。

再說說 input 元素,隨便在頁面上扔一個input,你都能發現它擁有一個預設的寬高,這就是它所具有的內在二維寬高屬性,並且該類元素會受UA影響,不同UA下所呈現外觀會有不同。

常見的置換元素有哪些?

img, object, button, input, textarea, select等

行內非置換元素真的不能應用margin嗎?

什麼是非置換元素?除了置換元素之外的元素,我想將這樣的元素稱之為非置換元素是沒有大礙的。

那麼行內非置換元素真的無法設定 margin 嗎?我想在工作中你一定碰到過很多這樣的場景,給一個 a 或者 span 定義間隙。這時我們寫:

CSS

span{margin:5px 10px;}

結果發現 span 的水平方向上的 margin 定義生效了,但垂直方向上的 margin 定義卻沒被應用。

是的,這就是行內非置換元素使用 margin 時的表徵,所以對各種特性的理解,在讓自己的程式碼更有效上是大有裨益的。

迴歸正題

我們本來是想說IE8按鈕margin auto居中失效Bug的,扯了不少題外話。

我們知道 margin keyword auto 不能應用在處於常規流中的 block-level 之外的元素上,所以我有這樣的一段程式碼:

CSS

button{display:block;margin:auto;}

HTML

<div id="demo">
    <button>按鈕</button>
</div>

恩,我們將 button 顯式的轉換為了 block,同時我們知道 button 作為置換元素,本身具備內在寬高,也就是說這時,我只需要加上 margin:auto ,該按鈕就應該在其包含塊裡水平居中。

是的,所有瀏覽器都和預期是一樣,實現了水平居中,但是卻出現了奇葩的IE8,完全無效,甚至不如原始社會的IE6。來看看示例 DEMO1IE8按鈕margin auto居中失效Bug

通過以上例子,你有沒有突然感覺到,如果要讓一個置換元素在包含塊中水平居中,出乎預料的簡單,只需要 display:block;margin:auto; 即可。

注意事項

令人意外的是,只有 button 和 input type 為 button 相關元素的時候,在IE8中才會水平居中失效;如: input type textimg 時,margin keyword auto 運作正常。

解決方案

  • 給其顯示的定義寬度
  • 不改變其display值,包含塊text-align:center
  • 其它水平居中方案,如:absolute + 負margin

margin系列文章:

相關文章