跳到主要內容
黯羽輕揚每天積累一點點

CSS 上下左右居中

免費2017-07-30#Solution#CSS#css绝对居中#css水平竖直居中#css水平垂直居中#垂直居中#IE7居中

2 種有意思的居中方案

寫在前面

有了 transformflex 後,水平豎直居中已經很容易了,比如萬能的:

position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
/* 1.內容左上角居中 */
top: 50%; left: 50%;
/* 2.負半寬高把內容挪回來 */
-webkit-transform: translate(-50%, -50%);

關鍵是利用 transform 百分比相對自身寬高計算的特性,如果環境不支持 transform 的話,就需要用一些比較老,但很精妙的技巧了

margin 居中

一個特徵明顯的方法:

position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
/* 1.要求自身內容相對包含塊居中 */
margin: auto;
/* 2.給出自身寬高計算方式 */
width: 100px; height: 100px;

原理

關鍵是利用 margin 的計算規則:

'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = 包含塊的寬度

'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = 包含塊的高度

(摘自 10.3.7 絕對定位的不可替換元素10.6.4 絕對定位的不可替換元素

margin 居中,就是要給上面的方程加上限制條件:

margin-top === margin-bottom && margin-left === margin-right

這是用 margin 實現居中的核心

CSS 裡 2 個步驟實際意義如下:

  1. 指定 margin 計算方式,其它必要值可計算的話,auto 要求 margin 平分剩餘空間

  2. 指定必要值計算方式

這裡的「必要值」要分開看,水平方向是 left, right, width,因為有如下規則:

如果'left','width'和'right'全都是'auto'……

如果這 3 個值都不是'auto'……

否則,把值為'auto'的'margin-left'和'margin-right'設置為 0,再在下面 6 條規則中挑 1 條合適的應用

5.如果'width'是'auto','left'和'right'都不是'auto',則求出'width'

也就是說,如果

left: 0;
right: 0;
width: auto;

那麼

margin-left: auto;
margin-right: auto;

的實際效果是

left: 0;
right: 0;
margin-left: 0;
margin-right: 0;
width: auto;

margin auto 失效(被抹掉變成 0 了),所以 width 是必要值,必須給出其計算方式,比如數值、百分比,或者限制條件,比如 max-width

豎直方向是 top, bottom, height,對應的規則與水平方向類似:

5.如果'height'是'auto','top'和'bottom'都不是'auto',則把值為'auto'的'margin-top'和'margin-bottom'設置為 0,再求出'height'

所以 height 也是必要值

這樣看來,最顯眼的 t: 0, b: 0, l: 0, r: 0不是重點,與 wdith, height 一樣,只是讓 margin auto 可計算的必要值而已,所以應該這樣排列:

position: absolute;
/* 1.要求自身內容相對包含塊居中 */
margin: auto;
/* 2.給出 margin auto 計算所需的必要值 */
top: 0; bottom: 0; left: 0; right: 0;
width: 100px; height: 100px;

而且,tblr 全 0 顯然不必要:

top: 30px; bottom: 30px; left: 50px; right: 50px;

也是可以的,更進一步,甚至可以用 tblr 來抵消上下(左右)padding, border-width 的差值

優缺點

缺點:

  • 無法應對內容不定高度的場景(height 必須 auto 的場景)

  • WP 下無效(假設可以忽略)

優點:

  • 兼容 [IE8+]

  • 支持 resize(用戶拖動內容右下角時仍然居中)

inline 居中

相當巧妙的方式:

.center-inline-container {
    /* 1.內容水平居中 */
    text-align: center;
}
.center-inline-container:before {
    /* 0 寬空格 */
    content: '\200B';
    display: inline-block;
    /* 2.把內容高度撐起來 */
    height: 100%;
    vertical-align: middle;
}
.center-inline-content {
    display: inline-block;
    /* 3.豎直居中 */
    vertical-align: middle;
}

原理

關鍵是利用 vertical-align: middle; 實現豎直居中:

把該盒的豎直中點和父級盒的基線加上父級的半 x-height 對齊

也就是說:

內容的縱向中點位置 = 父級盒的基線位置 + 父級的半 x-height 高度

首先確定父級盒的基線位置:

'inline-block'(盒)的基線是它的最後一個常規流中的行盒的基線,除非它沒有流內行盒或者它的'overflow'屬性的計算值不為'visible',此時基線是 bottom margin 邊

需要接著找「最後一個常規流中的行盒的基線」:

包含來自同一行的盒的矩形區域叫做行盒

CSS 2.1 沒有定義行盒基線的位置

遇到問題了,規範沒說行盒的基線在哪個位置,但給了限制條件:

內聯級盒是根據其'vertical-align'屬性豎直對齊的。如果它們是'top'或者'bottom'對齊,它們必須對齊得讓行盒高度最小化

滿足這些非直接限制後,再確定行盒的基線位置,那麼行盒基線位置的影響因素有:

  • 行盒裡的內聯級盒的 vertical-alignheightline-height

  • 行盒所在容器的 line-height

  • 其它(可能還有別的)

不同 case 下行盒基線位置可能不一樣,但很容易把最終基線的位置標出來:

Just add a character at the beginning of the line in questions

一般添個小寫字母 x,緊貼著 x 底部的位置就是基線

接下來確定「父級的半 x-height 高度」,這個相對容易:

ex:相關字體的'x-height'

'ex'單位是根據元素的第一個可用字體定義的。一種異常情況是當'ex'出現在'font-size'屬性的值中,此時參考父元素的'ex'

之所以叫'x-height',是因為通常等於小寫"x"的高度。然而,不含"x"的字體中也定義了'ex'

字體的 x-height 可以通過幾種不同的方式得到。有些字體包含關於 x-height 的可靠規格。如果可靠的字體規格無法獲得,UA 可以根據一個小寫字形的高度確定 x-height。一個可能的啟發是看小寫"o"的字形延伸到基線下方多遠,並減去其邊界框的 top 值。如果有時確定 x-height 是不可能或者不現實的,就應該用 0.5em

也就是說:

x-height = 當前字體的 x-height || 根據一個小寫字形的高度確定 x-height || 0.5em

那麼「半 x-height 高度」(0.5ex)大約是 0.25em

再看 CSS 裡的 3 個步驟:

  1. 水平居中不是問題

  2. 偽��素把行盒高度撐滿容器,配合 vertical-align: middle; 把行盒基線位置拉到容器中心附近

  3. 內容中心點與行盒基線上方 0.5ex 位置對齊

看到這裡很明確了,豎直方向根本沒居中

  • 行盒基線不等於容器中心

  • 行盒基線上方 0.5ex 處也不等於容器中心

最終兩個中心是對不上的,所以這種方式實現的居中有瑕疵,存在像素級的差異,如下圖:

[caption id="attachment_1456" align="alignnone" width="900"]css-center-inline css-center-inline[/caption]

可以嘗試用 margin-top 來修補,但因為行盒基線沒有確定的計算方法,做不到完美修復,從 Demo 來看,0.25ex 似乎最合適,實際應用中可能需要微調(如果在意像素級瑕疵的話)

優缺點

缺點:

  • 存在像素級瑕疵無法解決,不是完美豎直居中

  • 存在 HTML 空白字符佔空間的問題(壓縮 HTML,或者容器 font-size: 0,內容重置 font-size),影響水平居中

  • 需要額外元素/偽元素

優點:

  • 兼容 [IE8+]

  • 支持不定高度內容

在線 Demo

Demo 地址:http://ayqy.net/temp/css-center.html

P.S. 樣式、結構及注意事項都在源碼裡

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論