我們都知道 margin:0 auto; 的樣式能讓元素水平置中,而 margin: auto; 卻不能做到垂直置中……直到現在。但是,請注意!想讓元素絕對置中,只需要聲明元素高度,並且附加以下樣式,就可以做到:
.Absolute-Center { margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0;}
我並不是第一個發現這種方法的人(不過我還是敢把它叫做“完全置中”),它有可能是種非常普遍的技巧。但大多數介紹垂直置中的文章中並沒有提到過這種方法
Simon提供了一個jsFiddle的連結,其他的方法相比之下就相形見絀了。(Priit也在評論欄中提到了同樣的方法)。深入研究了一番之後,我又用某些關鍵詞找到了記載這種方法的三個網站:網站一、網站二、網站三。
以前從未用過這種方法的我想試試,看看這種”完全置中”的方法到底有多麼神奇。 好處:
跨瀏覽器,相容性好(無需hack,可兼顧IE8~IE10)
無特殊標記,樣式更精簡
調適型配置,可以使用百分比和最大最小高寬等樣式
置中時不考慮元素的padding值(也不需要使用box-sizing樣式)
布局塊可以自由調節大小
img的映像也可以使用
同時注意:
必須聲明元素高度
推薦設定overflow:auto;樣式避免元素溢出,顯示不正常的問題
這種方法在Windows Phone上不起作用
瀏覽器支援:Chrome、Firefox、Safari、Mobile Safari、IE8-10。 “完全置中”經測試可以完美地應用在最新版本的Chrome、Firefox、Safari、Mobile Safari中,甚至也可以運行在IE8~IE10上
對照表
“完全置中”並不是本篇文章中唯一的選項。要做到垂直置中,還存在著其他方法,各有各的長處。採取什麼樣的方法,取決於你所支援的瀏覽器,以及現有標籤的結構。下面這張對照表能夠幫你選出最符合你需要的方法。
說明
在研究了規範和文檔後,我總結出了“完全置中”的工作原理:
在普通文檔流裡,margin: auto; 的意思是設定元素的margin-top和margin-bottom為0。
W3.org:?If ‘margin-top’, or ‘margin-bottom’ are ‘auto’, their used value is 0.
2. 設定了position: absolute; 的元素會變成塊元素,並脫離普通文檔流。而文檔的其餘部分照常渲染,元素像是不在原來的位置一樣。 Developer.mozilla.org:?…an element that is positioned absolutely is taken out of the flow and thus takes up no space
3. 設定了top: 0; left: 0; bottom: 0; right: 0; 樣式的塊元素會讓瀏覽器為它包裹一層新的盒子,因此這個元素會填滿它相對父元素的內部空間,這個相對父元素可以是是body標籤,或者是一個設定了position: relative; 樣式的容器。 Developer.mozilla.org:?For absolutely positioned elements, the top, right, bottom, and left properties specify offsets from the edge of the element’s containing block (what the element is positioned relative to).
4. 給元素設定了寬高以後,瀏覽器會阻止元素填滿所有的空間,根據margin: auto; 的要求,重新計算,並包裹一層新的盒子。 Developer.mozilla.org:?The margin of the [absolutely positioned] element is then positioned inside these offsets.
5. 既然塊元素是絕對位置的,又脫離了普通文檔流,因此瀏覽器在包裹盒子之前會給margin-top和margin-bottom設定一個相等的值。 W3.org:?If none of the three [top, bottom, height] are ‘auto’: If both ‘margin-top’ and ‘margin-bottom’ are ‘auto’, solve the equation under the extra constraint that the two margins get equal values.?AKA: center the block vertically
使用“完全置中”,有意遵照了標準margin: auto; 樣式渲染的規定,所以應當在與標準相容的各種瀏覽器中起作用。
對齊
容器內對齊
使用“完全置中”,就可以在一個設定了position: relative的容器中做到完全置中元素了! (置中例子,請前往英文原文查看)
.Center-Container { position: relative;} .Absolute-Center { width: 50%; height: 50%; overflow: auto; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0;}
接下來的樣本會假設已經包含了以下樣式,並且以逐步添加樣式的方式提供不同的特性。
在可視地區內置中
想要使內容區在可視地區內置中嗎?設定position: fixed樣式,並設定一個較高的z-index值,就可以做到。
.Absolute-Center.is-Fixed { position: fixed; z-index: 999;}
移動版Safari的說明:如果外面沒有一層設定position: relative的容器,內容區會以整個文檔的高度的中心點為基準置中,而不是以可視地區的高度中心點為基準置中。
位移值
如果需要添加固定的標題,或者其他帶位移樣式的元素,可以直接把類似top: 70px; 的樣式寫進內容地區的樣式中。一旦聲明了margin: auto; 的樣式,內容塊的top left bottom right的屬性值也會同時計算進去。
如果想讓內容塊在貼近側邊的過程中保持水平置中,可以使用right: 0; left: auto; 讓內容貼在右側,或者使用left: 0; right: auto; 使內容貼在左側。
.Absolute-Center.is-Fixed { position: fixed; z-index: 999;}
帶響應式
使用absolute的最大好處就是可以完美地使用帶百分比的寬高樣式!就算是min-width/max-width或者min-height/max-height也能夠有如預期般的表現。
再進一步加上padding樣式的話,absolute式的完全置中也絲毫不會破壞!
.Absolute-Center.is-Responsive { width: 60%; height: 60%; min-width: 200px; max-width: 400px; padding: 40px;}
帶溢出內容
內容區高度大於可視地區或者一個position: relative的容器,其內容可能會溢出容器,或被容器截斷。只要內容地區沒有超出容器(沒有給內容容器預留padding的話,可以設定max-height: 100%;的樣式),那麼容器內就會產生捲軸。
.Absolute-Center.is-Overflow { overflow: auto;}
大小可調整
使用其他樣式,或者使用JavaScript調整內容區的大小,也是不用手動重新計算的!如果設定了resize的樣式,甚至可以讓使用者自行調節內容地區的大小。 “完全置中”法,無論內容區怎麼改變大小,都會保持置中。
設定了min-/max- 開頭的屬性可以限制區塊的大小而不用擔心撐開容器。
.Absolute-Center.is-Resizable { min-width: 20%; max-width: 80%; min-height: 20%; max-height: 80%; resize: both; overflow: auto;}
如果不設定resize: both的樣式,可以設定transition樣式平滑地在大小間切換。一定要記得設定overflow: auto樣式,因為改變大小後的容器高寬很有可能會小於內容的高寬。 “完全置中”法是唯一一種能支援使用resize: both樣式的方法。
使用注意:
需要設定max-width/max-height給內容地區留足夠的空間,不然就有可能使容器溢出。
resize屬性不支援移動版瀏覽器和IE8-10,如果使用者體驗很重要的話,請確保使用者可以有其他替代方法來改變大小。
同時使用resize樣式和transition會使使用者在開始改變大小時產生等於transition效果時間等長的延時。
映像
映像也同樣有效!提供相應的class,並指定樣式 height: auto; ,就得到了一張隨著容器改變大小的響應式圖片。
請注意,height: auto; 樣式雖然對圖片有效,如果沒有用到了後面介紹的‘可變高技巧’,則會導致普通內容地區伸長以適應容器長度。
瀏覽器很有可能是根據渲染結果填充了映像高度值,所以在測試過的瀏覽器中,margin: auto; 樣式就像是聲明了固定的高度值一般正常工作。
HTML:
<img src="http://placekitten.com/g/500/200" alt="" />
CSS:
.Absolute-Center.is-Image { height: auto;} .Absolute-Center.is-Image img { width: 100%; height: auto;}
可變高度
“完全置中”法的確需要聲明容器高度,但是高度受max-height樣式的影響,也可以是百分比。這非常適合響應式的方案,只需要設定好帶溢出內容就行。
另一種替代方案是設定display: table樣式置中,,不管內容的長度。這種方法會在一些瀏覽器中產生問題(主要是IE和Firefox)。我在ELL Creative的朋友Kalley寫了一個基於Modernizr 的測試,可以用來檢查瀏覽器是否支援這種置中方案。現在這種方法可以做到漸進增強。
注意要點: 這種方法會破壞瀏覽器安全色性,如果Modernizr測試不能滿足你的需求,你可能需要考慮其他的實現方案。
與大小可調整技術是不相容的
Firefox/IE8中使用display: table,內容區在垂直方向靠上,水平方向仍然置中。
IE9/10中使用display: table,內容區會跑到左上方。
移動版Safari中內容區是水平對齊的,但是如果使用了百分比的寬度,水平方向上會稍稍偏離中心。
Javascript:
/* Modernizr Test for Variable Height Content */Modernizr.testStyles('#modernizr { display: table; height: 50px; width: 50px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; }', function(elem, rule) { Modernizr.addTest('absolutecentercontent', Math.round(window.innerHeight / 2 - 25) === elem.offsetTop);});
CSS:
.absolutecentercontent .Absolute-Center.is-Variable { display: table; height: auto;}
其他方法
“完全置中”法是解決置中問題的好方法,同時也有許多可以滿足不同需求的其他方法。最常見的,推薦的方法有負margin值、transform法、table-cell法、inline-block法、以及現在出現的Flexbox法,這些方法其他文章都有深入介紹,所以這裡只會稍稍提及。
負margin值
這或許是最常用的方法。如果知道了各個元素的大小,設定等於寬高一半大小的負margin值(如果沒有使用box-sizing: border-box樣式,還需要加上padding值),再配合top: 50%; left: 50%;樣式就會使塊元素置中。
需要注意的是,這是按照預想情況也能在工作在IE6-7下的唯一方法。
.is-Negative { width: 300px; height: 200px; padding: 20px; position: absolute; top: 50%; left: 50%; margin-left: -170px; /* (width + padding)/2 */ margin-top: -120px; /* (height + padding)/2 */}
好處:
瀏覽器安全色性非常好,甚至支援IE6-7
需要的編碼量很少
同時注意:
這是個非響應式的方法,不能使用百分比的大小,也不能設定min-/max-的最大值最小值。
內容可能會超出容器
需要為padding預留空間,或者需要使用box-sizing: border-box樣式。
transform法
和“完全置中”法的好處一樣,簡單有效,同時支援可變高度。為內容指定帶有廠商首碼的transform: translate(-50%,-50%)和top: 50%; left: 50%;樣式就可以讓內容塊置中。
.is-Transformed { width: 50%; margin: auto; position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%,-50%); -ms-transform: translate(-50%,-50%); transform: translate(-50%,-50%);}
好處:
內容高度可變
代碼量小
同時注意:
不支援IE8
需要寫廠商首碼
會和其他transform樣式有衝突
某些情況下的邊緣和字型渲染會有問題
table-cell法
這種可能是最好的方法,因為高度可以隨內容改變,瀏覽器支援也不差。主要缺陷是會產生額外的標籤,每一個需要置中的元素需要三個額外的HTML標籤。
HTML:
<div class="Center-Container is-Table"> <div class="Table-Cell"> <div class="Center-Block"> <!-- CONTENT --> </div> </div></div>
CSS:
.Center-Container.is-Table { display: table; }.is-Table .Table-Cell { display: table-cell; vertical-align: middle;}.is-Table .Center-Block { width: 50%; margin: 0 auto;}
好處:
內容高度可變
內容溢出則能自動撐開父元素高度
瀏覽器安全色性好
同時注意:
需要額外的HTML標籤
inline-block法
迫切需要的方法:inline-block法置中。基本方法是使用 display: inline-block, vertical-align: middle樣式和虛擬元素讓內容塊在容器中置中。我的實現用到了幾個在其他地方見不到的新技巧解決了一些問題。
內容區聲明的寬度不能大於容器的100% 減去0.25em的寬度。就像一段帶有長文本的地區。不然,內容地區會被推到頂端,這就是使用:after偽類的原因。使用:before偽類則會讓元素有100%的大小!
如果內容塊需要儘可能大地佔用水平空間,可以為大容器加上max-width: 99%;樣式,或者考慮瀏覽器和容器寬度的情況下使用max-width: calc(100% – 0.25em) 樣式。
這種方法和table-cell的大多數好處相同,不過最初我放棄了這個方法,因為它更像是hack。不管這一點的話,瀏覽器支援很不錯,而且也被證實是很流行的方法。
HTML:
<div class="Center-Container is-Inline"> <div class="Center-Block"> <!-- CONTENT --> </div></div>
CSS:
.Center-Container.is-Inline { text-align: center; overflow: auto;} .Center-Container.is-Inline:after,.is-Inline .Center-Block { display: inline-block; vertical-align: middle;} .Center-Container.is-Inline:after { content: ''; height: 100%; margin-left: -0.25em; /* To offset spacing. May vary by font */} .is-Inline .Center-Block { max-width: 99%; /* Prevents issues with long content causes the content block to be pushed to the top */ /* max-width: calc(100% - 0.25em) /* Only for IE9+ */ }
好處:
內容高度可變
內容溢出則能自動撐開父元素高度
瀏覽器安全色性好,甚至可以調整支援IE7
同時注意:
需要額外容器
依賴於margin-left: -0.25em的樣式,做到水平置中,需要為不同的字型大小作調整
內容區聲明的寬度不能大於容器的100% 減去0.25em的寬度
Flexbox法
CSS未來發展的方向就是採用Flexbox這種設計,解決像垂直置中這種共同的問題。請注意,Flexbox有不止一種辦法置中,他也可以用來分欄,並解決奇奇怪怪的布局問題。
.Center-Container.is-Flexbox { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-align: center; -moz-box-align: center; -ms-flex-align: center; -webkit-align-items: center; align-items: center; -webkit-box-pack: center; -moz-box-pack: center; -ms-flex-pack: center; -webkit-justify-content: center; justify-content: center;}
好處:
內容可以是任意高寬,溢出也能表現良好
可以用於各種進階布局技巧
同時注意: 不支援IE8-9
需要在body上寫樣式,或者需要額外容器
需要各種廠商首碼相容現代瀏覽器
可能有潛在的效能問題
最後的建議
各項技術都有各自的好處,採取什麼樣的方法,取決於你所支援的瀏覽器,以及現有標籤的結構。請使用上面提供對照表幫你選出最符合你需要的方法。
“完全置中”法簡單方便,迅速及時。以前使用負Margin值的地方,都可以使用Absolute置中。無需繁瑣的數學計算,無需額外標籤,而且可以隨時改變大小。
如果網站需要可變高度的內容,而且同時照顧到瀏覽器安全色性的話,可以嘗試table-cell和inline-block技術,如果想嘗試新鮮事物的話,可以使用Flexbox,並享受這種進階技術帶來的好處。