為什麼「margin:auto」可以讓塊級元素水平居中?

  1. 居中是如何計算的?

  2. 為何不能垂直居中?


瀉藥

這是個很老的問題了

貌似答案挺多的

這誰葯偶來回答啊…… = =|||

不答又不合適

簡單扯扯點其他貌似沒扯到的

在 CSS 2 規範的 10 章 可視化布局內

對 塊級非替換元素在普通流內布局有公式描述

Visual formatting model details

"margin-left" + "border-left-width" + "padding-left" + "width" + "padding-right" + "border-right-width" + "margin-right" = width of containing block

就是 左m+左b+左p+w+右p+右b+右m = 包含塊寬度

以及對這公式的 5 條 if

跟這問題直接相關的是2個。先說第一個

  • 如果啊,width 是 auto 值,那麼其他是 auto 的值就為 0.

所以呢,先說 width auto margin auto 的時候啊,margin 就 0 了。

整個容器充滿包含塊唄。也就沒水平居中啥事兒了。

然後呢,說水平居中的事兒。

這裡又有個if

  • 如果 "margin-left" "margin-right" 都是 auto 值,使用的值相等,那麼就水平居中包含塊。

基本上規定的死死了。

所以連起來就是:

如果有 width 那麼 ml/mr 是 auto(其他值么),那就是0,後面的一條 if 不生效了。

如果 width 不是 auto,那就是有確定寬度了。 ml/mr 是 auto,那就居中。

其實根據最初的公式很好理解,

元素的包含塊寬度是最初能定下來。

(你想啊,根 HTML 的包含塊不就是視口么,瀏覽起內窗口寬度啊,總能知道吧。然後根據這個初始包含塊寬度往下算)

所以,就有一系列確定值。

確定標黑,不確定為(x),來說明 width,沒b沒p的情況(簡化下么)

沒有的值標為 0

"margin-left"(x) + "border-left-width"(0) + "padding-left"(0) + "width"(假設 300px) + "padding-right"(0) + "border-right-width" (0)+ "margin-right"(x) = width of containing block(假設 600 px)

整理下

x+0+0+300+0+0+x = 600

求x

2x+300 = 600

2x = 300

x = 150 (px)

好了,ml 和 mr 就算出 150 px 了

(如果 其他 bl、br、pl、pr 有值就帶公式里,一樣的)

排布下,正好容器在包含塊中間位置。

這就是最後內個 if 要說的內容。

為何不能垂直居中……

這個主要是規範里沒給這方面規定……

並與其他初始設定衝突。

如:

width 相關計算依賴於其包含塊,這玩意是最初能確定值。

而 height 相關計算依賴於其自身內容高度,自身內容高度是不能最初確定值的。

所以無法建立類似上面的公式來使用 mt、mb auto 實現高度居中。

且,mt、mb 的百分比值參照還是依賴包含塊實際寬度的。

同理,因為包含塊高度未知,沒辦法以確定值來計算 mt、mb。


keyword auto默認是使用剩餘空間,所以不論left還是right定義了auto,計算值都會是包含塊的剩餘空間,如果左右都設置了auto,那麼就會均分剩餘空間。當然,這指的是書寫模式為lr-tb的情況下,這種情況,寬度是一定的。至於縱向,高度其實是沒有一個固定值,auto無可refer的參照物,如果top或bottom設置了auto,那計算值其實會是0。


這塊在標準里稱作「Calculating widths and margins」,講width/height,margin,left/right/top/bottom不同組合時的布局計算規則,具體鏈接如下:

http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins

實際項目中,主要有兩種應用場景:

1、普通流布局通過「width&

2、absolute元素在具體寬高容器中垂直水平居中對齊。

實現方式可參考下:CodePen - Absolute Centering

詳細的計算規則看標準:http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width

以上兩種場景,有一條規則是一樣的,無論垂直還是水平方向,margin有節餘同時對應方向設置了auto,相應方向計算出的margin是分半的(第一種垂直方向除外,why?標準規定!)。

因此,題主提到的垂直居中也是可以實現的,只是有了限制條件(應用場景二)。


這個是轉自 @杜瑤 大神的博客(他也回答了 ,我就當幫他做個宣傳吧O(∩_∩)O~) ,這位大神寫了好多關於margin的使用技巧,我想下面這段可以解決樓主的問題吧~

正文開始

auto是margin的可選值之一。相信大家平時使用auto值時,最多的用法大概是 margin: 0 auto; 和 margin: auto;,恩,是的,塊元素水平居中。讓我們來看看代碼實現:

CSS:

#demo{
width: 500px;
margin: auto; /* 或者 margin: 0 auto; */
}

HTML:

&
&

恩,我就是那個需要水平居中的傢伙。& &

為了更明顯點,我們來看個例子:margin實現塊元素水平居中。Cool,這麼簡單就實現了水平居中。

不過你可能也發現了不論是 margin: auto; 還是 margin: 0 auto; 效果都是一樣的,都是讓 #demo 水平居中了,但縱向並沒有任何變化。

大家都知道 margin 是複合屬性,也就是說 margin: auto; 其實相當於 margin: auto auto auto auto;,margin: 0 auto;相當於 margin: 0 auto 0 auto;,四個值分別對應上右下左。至於CSS中的上、右、下、左順序就不做贅述了。

根據規範,margin-top: auto; 和 margin-bottom: auto;,其計算值為0。這也就解釋了為什麼 margin: auto; 等同於 margin: 0 auto;。但僅此而已嗎?讓我們來看看規範描述:

原文:On the A edge and C edge, the used value of 『auto』 is 0.

翻譯:如果場景是A和C,那麼其 auto 計算值為 0。

更詳細請參閱:margin properties

由此可見,它們還與書寫模式 writing-mode 和 文檔流方向 direction 有關。所以我們說 margin: auto; 等同於 margin: 0 auto; 是不太精準的,因為還有前置條件。

了解這些很重要,這有助於理解 margin 屬性的設計意圖。

OK,聊了這麼多,我們回到默認的 writing-mode: horizontal-tb; 和 direction: ltr; 的情況繼續往下,後面的話題都基於這個前提。

為什麼auto能實現水平居中?

這是因為水平方向的 auto,其計算值取決於可用空間(剩餘空間)。

原文:On the B edge and D edge, the used value depends on the available space.

翻譯:如果場景是B和D,那麼其 auto 計算值取決於可用空間。


CSS權威指南-chapter 7裡面有說到:

&> 正常流中的塊級元素框的水平總和就等於父元素的width

&> 在水平格式化的「7大屬性」中,只有3個可以設置為auto: width, margin-left, margin-right;

因此, 只要我們設置了block element的width, 並且margin-leftauto; margin-right: auto; 就可以讓block element水平居中。

但是, 對於垂直格式化是不行的。

如果我們把margin-top和margin-right都設置為auto的話,實際上他們的高度將是0。(設定就是這樣吧- -),可以測試測試。

想要垂直居中也可以, margin-top: 25%; margin-bottom: 25%;

refrence: *css權威指南*


我覺得這事兒就像要定義邊距為什麼要使用margin關鍵字,規則就是這樣的,沒有因為所以


以下答案並不是針對問題的回答

好像沒有人提到一種使 margin:auto; 能垂直水平居中的方法,還是說一下吧,萬一能幫到一些人

父元素: {
display: flex;
}
子元素: {
flex: 0 0 auto;
margin: auto;
}

就這樣。


因為CSS規範中說明了:一個有特定寬度的元素,若左右邊距為auto,瀏覽器會取它的容器和該容器的寬度之差,除以2,作為該元素的左邊距和右邊距


margin: auto是margin: auto auto auto auto的縮寫,左右都auto,寬度相等,並且儘可能撐大,那就是居中了


高度也可以居中啊

width:x;

height:x;

left:0;

right:0;

top:0;

bottom:0;

margin:auto;

就可以了


推薦閱讀:

如何讓input裡面placeholder水平居中?
css 使用display:inline-block的問題求解?
現在國外做網站是用 DIV + CSS,還是 table?
有哪些好的 HTML 和 CSS 入門教程可以推薦給新手?
CSS3 中calc()關鍵字+(加)、-(減)運算符為何必須加空格?

TAG:前端開發 | CSS | CSS3 | CSS布局 |