css居中

居中包括水平居中和垂直居中。

水平居中

水平居中沒有什麼好說的,比較簡單,兼容性也沒什麼問題。

block 元素我們通常用 margin:0 auto 實現水平居中,而 inline(包括inline-block) 元素一般通過設置其父元素的 text-align:center

垂直居中

垂直居中則比較複雜,居中的難度主要在這裏。但是我們要抓住本質,就不難理解這些所謂的奇技淫巧。

我們可以用數字來描述垂直居中:父元素的高度是 H,子元素的高度是 h,當父元素的上邊界與子元素的上邊界的距離爲 (H-h)/2 時則實現了垂直居中。

所以無論我們用了什麼手段,最終都是要實現這個目標。

按照難度我做了如下的劃分(由於文字垂直居中比較弱智,並且可以用塊級元素的某些方式實現,這裏不再單獨討論):

1.簡單方式實現垂直居中

html元素在瀏覽器中的佈局由一系列的規則決定,最基礎的盒模型描述了元素的四個佈局要素:margin box,border box,padding box,content box,這四個盒基本可以設定元素的位置,佈局排版就是控制不同元素的位置和層次。

根據盒子的定義,對於以下情況可以直接用margin/border/padding完成居中:

a.父容器大小由內部元素決定(撐開),並且對於居中時父元素border與子元素border的距離沒有什麼硬性要求。

缺點:父元素的大小不能被設定。

例子如下:

 1 <style type="text/css">
 2     .father{
 3         padding: 10% 0;
 4         border: 1px solid;
 5     }
 6     .child{
 7         height: 50px;
 8         width: 100px;
 9         background: #ddd;
10         margin: 0 auto;
11     }
12 </style>
13 <div class="father">
14     <div class="child"></div>
15 </div>

 

b.子元素大小固定

這種情況下,經常使用的方法是定位:

對子元素relative定位,top、left各50%,這個時候如果父元素以中心分成四個象限,那麼此時子元素在第四象限,左上角頂着父元素的花心。而我們又知道子元素的寬高,只要用負margin各拉回元素寬高的一半,兩顆心就對齊了,完成了居中。

這裏無論如何也避不開子元素大小不固定這個條件了,垂直居中的各種淫技基本爲了搞定它。我們進入下一個標題:

2.複雜方式的垂直居中

a.使用vertical-align

憑直覺我們會想到這個屬性,但是理解這個屬性有點複雜,建議深入瞭解。

vertical-align用來設置行內元素在其所處行框中的垂直對齊方式,行框中從上到下主要的對齊線依次是頂線、中線、基線、底線,默認情況下vertical-align的值是基線。這些對齊線的間距又由行高決定,我們看w3c中一段有在行高的描述:

A line box is always tall enough for all of the boxes it contains. However, it may be taller than the tallest box it contains (if, for example, boxes are aligned so that baselines line up). When the height of a box B is less than the height of the line box containing it, the vertical alignment of B within the line box is determined by the 'vertical-align' property. When several inline-level boxes cannot fit horizontally within a single line box, they are distributed among two or more vertically-stacked line boxes. Thus, a paragraph is a vertical stack of line boxes. Line boxes are stacked with no vertical separation (except as specified elsewhere) and they never overlap.

行高大於等於行內最高的行內盒高度,當行內盒子B的高度小於其存在的行框的高度時,B在行內垂直的對齊方式由“vertiacl-align”決定。

ok.到這裏,背景知識已經搞定了。我們來看操作:

對於本小節前面提到的場景,我們把子元素B設置成inline-block,這個內聯元素會導致生成一個行框X,X只包含這一個內聯元素B,此時它的行高與內部元素高度一致——根據規則,這時vertical-align不起作用,我們有什麼辦法能把這個行框的高度設成B要相對居中的元素的高度呢?

我們可以做一個寬度爲0的高度100%的inline-block元素B2放在X中,X就會被撐開,因爲X是匿名的,我們做的B2百分比計算高度時參照對象仍是dom上的父節點。這時我們設置B和B2的vertical-align都爲middle就能實現居中了。爲什麼都要設置爲middle,可以參考上面那段英文來思考——行框在什麼情況下高度會大於內部最高行盒的高度。

b.使用margin:auto 

還是憑直覺,爲什麼 margin:0 auto 可以實現水平居中,margin:auto 0 不能實現垂直居中,甚至更省事 margin:auto 怎麼不能實現居中?

我評判一個系統設計好壞的重要標準是:在類似的場景下應當有一致的,至少是抽象一致的處理方式。當年我第一次接觸到這個命題的時候足足花了兩個小時來研究,我覺得用這種方式應該可以實現居中。我思考的過程是這樣的,

  • 塊級元素在普通流中會自動繼承寬度,但不會繼承高度,margin:0 auto肯定和這個有關。
  • 進而發現了書寫模式這個尚未成爲標準的屬性:-webkit-writing-mode(下節有對其的說明)。
  • w3c-org中的一段定義:(對於 absolutely positioned 的元素) 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block

第三點是從 這位同學的博客上 發現的,我正好讀到規範的第九章,這個博客的總結很到位,我過往對垂直居中的研究基本全覆蓋了。

根據第三點,我們讓子元素的top和bottom都爲0,height of containing block - ( 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' ) = 'margin-top' + 'margin-bottom',此時設置 margin:auto 0 則能實現垂直居中,例子如下:

<style type="text/css">
.c{
    position: relative;
    border: 1px solid;
    height: 100px;
    width: 100px;
}
.mid{
    width: 50px;
    height: 20px;
    background: #ddd;
    position: absolute;
    margin: auto 0;
    top:0;
    bottom: 0;
}
</style>
<div class="c">
    <div class="mid"></div>
</div>

 

ps:這個兼容性不好,IE8+支持,chrome和firfox支持良好。

x.一點延伸:-webkit-writing-mode

請看下面的例子:

看第一個例子,我們使用-webkit-writing-mode來切換元素的排版規則,讓容器內部的div原本在水平方向上展開能力喪失,替換爲垂直方向上的展開能力,這樣{margin:auto 0px;}就具有了垂直居中的功能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章