前言
石匠敲擊石頭的第 16 次
在日常開發中,經常會遇到水平垂直居中的佈局,雖然現在基本上都用 Flex 可以輕鬆實現,但是在某些無法使用 Flex 的情況下,又應該如何讓元素水平垂直居中呢?這也是一道面試的必考題,所以打算寫一篇文章來好好梳理一下,如果哪裏寫的有問題歡迎指出,不勝感激。
分類
實現元素水平垂直居中的方法有很多,大致可以分為以下兩類:
- 固定寬高元素適用的方法
- 不固定寬高元素適用的方法
我們先實現基礎的佈局,然後再分別講每一類具體的方案。
.container {
border: 1px solid red;
width: 300px;
height: 300px;
}
.box {
background: blue;
color: #fff;
}
.size {
width: 100px;
height: 100px;
}
<div class="container">
<div class="box size">你好,世界</div>
</div>
固定寬高元素
absolute + 負 margin
.container {
/* 其它的基礎樣式... */
position: relative;
}
.box {
/* 其它的基礎樣式... */
position: absolute;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
}
該方案的原理非常簡單,可以分為兩步來看:
-
先通過絕對定位的
top: 50%和left: 50%使元素的左上角定位在.container容器元素的中心位置 -
再通過
margin-top和margin-left設置為負值,具體值為元素寬度和高度的一半,例如這裏元素的寬高都是100px,所以一半就是50px最終的效果如下
在線查看效果
✅ 優點: 兼容性好,適用於 IE 等老版本瀏覽器。
⚠️ 缺點:
- 需要提前知道元素大小,並且需要手動計算元素大小的一半
- 每次修改元素大小都需要同步修改
margin值
absolute + margin: auto
.container {
/* 其它的基礎樣式... */
position: relative;
}
.box {
/* 其它的基礎樣式... */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
該方案和前一個方案最終效果是一樣,該方案的步驟如下:
- 通過設置絕對定位
top:0; bottom:0; left:0; right:0;,讓瀏覽器知道元素被限制”在父容器內四邊,這樣有了一個明確的空間範圍 - 再通過設置
margin: auto,瀏覽器就可以根據父容器大小 - 元素大小 = 剩餘空間,把剩餘空間平分給margin: auto,實現水平垂直方向上的居中
在線查看效果
✅ 優點:
- 兼容性好,適用於 IE 等老版本瀏覽器
- 每次修改元素大小不需要同步修改
margin值,無需手動計算元素大小的一半
⚠️ 缺點: 只能用於固定尺寸的元素,不適合寬高不確定的情況。
absolute + calc
.container {
/* 其它的基礎樣式... */
position: relative;
}
.box {
/* 其它的基礎樣式... */
position: absolute;
top: calc(50% - 50px);
left: calc(50% - 50px);
}
該方案與前面的 absolute + 負 margin 方案原理相同,使用了 calc 函數替代了 margin 負值來計算居中的位置。
在線查看效果
⚠️ 缺點:
- 該方案依賴
calc函數的兼容性,具體兼容性可以參考 Can I use - 需要提前知道元素大小,修改元素大小需要同步修改
calc函數中減去的值 - 相比前兩個方案,該方案既缺乏兼容性(IE9+),又需要手動計算元素大小的一半,不推薦使用
不固定寬高元素
absolute + transform
.container {
/* 其它的基礎樣式... */
position: relative;
}
.box {
/* 其它的基礎樣式... */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
該方案與前面的 absolute + 負 margin 方案原理相同,使用了 transform 替代了 margin 負值來計算居中的位置。
因為translate(-50%, -50%) 的百分比是相對於元素本身的寬高,所以不需要提前知道元素的具體尺寸。
在線查看效果
✅ 優點: 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
⚠️ 缺點: 該方案依賴 transform() 函數的兼容性,具體兼容性可以參考 Can I use
line-height
.container {
/* 其它的基礎樣式... */
line-height: 300px;
text-align: center;
}
.box {
/* 其它的基礎樣式... */
display: inline-block;
vertical-align: middle;
line-height: initial;
}
該方案的實現步驟如下:
-
首先給
.container容器設置一個與高度相同的行高,例如這裏容器的高度為300px,所以設置line-height: 300px,並給容器設置text-align: center;水平居中對齊 -
然後再給
.box元素設置為行內塊(inline-block)元素,並設置vertical-align: middle;垂直居中對齊 -
居中效果有了,但是文字卻不見了,因為
.container容器的text-align和line-height默認是會被繼承給.box元素,這時我們需要通過line-height: initial和text-align: initial重置為初始值
在線查看效果
✅ 優點: 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
⚠️ 缺點: 需要重置內部元素的文字樣式
writing-mode
.container {
/* 其它的基礎樣式... */
writing-mode: vertical-lr;
text-align: center;
}
.inner {
width: 100%;
display: inline-block;
writing-mode: horizontal-tb;
}
.box {
/* 其它的基礎樣式... */
display: inline-block;
text-align: initial;
}
<div class="container">
<div class="inner">
<div class="box">你好,世界</div>
</div>
</div>
該方案主要利用 writing-mode 屬性,writing-mode 屬性可以改變文字的顯示方向
writing-mode: vertical-lr讓元素文字垂直方向顯示writing-mode: horizontal-tb讓元素文字水平方向顯示
該方案實現的步驟如下:
-
首先將
.container容器的文字顯示方向調整為垂直方向,並設置文字水平居中對齊,用來實現垂直居中 -
添加一個
.inner包裝元素,設置為行內塊(inline-block)元素,並將寬度設置為100%,並設置文字顯示方向為水平方向,此時.container容器的text-align: center;被繼承,變成了水平居中 -
最後將
.inner包裝元素內部的.box元素調整為行內塊(inline-block)元素,並重置繼承的text-align屬性的值為初始值
在線查看效果
✅ 優點:
- 兼容性好,適用於 IE 等老版本瀏覽器
- 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
⚠️ 缺點:
- 需要重置內部元素的文字樣式
- 實現和理解起來有點複雜
- 需要額外的 DOM 元素
table
.container {
/* 其它的基礎樣式... */
text-align: center;
}
.box {
/* 其它的基礎樣式... */
display: inline-block;
text-align: initial;
}
<table>
<tbody>
<tr>
<td class="container">
<div class="box">你好,世界</div>
</td>
</tr>
</tbody>
</table>
該方案利用了 <table> 標籤中 <td> 單元格內容天然是垂直居中的特性,所以只需要再添加一個水平居中就可以實現水平垂直居中。
在線查看效果
✅ 優點:
- 兼容性好,適用於 IE 等老版本瀏覽器
- 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
⚠️ 缺點:
- 代碼冗餘,需要額外的 DOM 元素
- 不符合
<table>標籤正確語義用法 - 需要重置內部元素的文字水平居中樣式
display: table-cell
.container {
/* 其它的基礎樣式... */
display: table-cell;
text-align: center;
vertical-align: middle;
}
.box {
/* 其它的基礎樣式... */
display: inline-block;
text-align: initial;
}
該方案通過將 .container 容器變成 table 單元格顯示效果,因為表格單元格的內容默認是垂直居中,在這基礎上再加一個 text-align: center; 水平居中即可實現水平垂直居中效果。
在線查看效果
✅ 優點:
- 兼容性好,適用於 IE 等老版本瀏覽器
- 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
- 相比
<table>實現沒有多餘的 DOM 元素
⚠️ 缺點: 需要重置內部元素的文字水平居中樣式
Flex
.container {
/* 其它的基礎樣式... */
display: flex;
justify-content: center;
align-items: center;
}
上面這段代碼相信大家用的比較多了,我就不詳細介紹了。不過 Flex 還有另外一種更加簡便的實現方法:
.container {
/* 其它的基礎樣式... */
display: flex;
}
.box {
/* 其它的基礎樣式... */
margin: auto;
}
這個方案利用了 Flex 佈局中,Flex 子元素的 margin 被設置為 auto,瀏覽器會將剩餘空間平均分配的特性。
在線查看效果
✅ 優點:
- 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
- 實現簡單,代碼量少
⚠️ 缺點: 只適合在現代瀏覽器中使用。
Grid
.container {
/* 其它的基礎樣式... */
display: grid;
}
.box {
/* 其它的基礎樣式... */
align-self: center;
justify-self: center;
}
在線查看效果
✅ 優點:
- 無需提前知道元素大小,修改元素大小不需要同步修改相關的值
- 實現簡單,代碼量少
⚠️ 缺點: 只適合在現代瀏覽器中使用,更加推薦使用 Flex。
總結
元素水平垂直居中的方案主要可以分為以下兩類:
固定寬高元素適用的方案
| 方案 | 兼容性 | 備註 |
|---|---|---|
absolute + 負 margin |
✅ 非常好(IE6+) | 最老牌的方案,手動計算偏移量 |
absolute + margin: auto |
✅ 非常好(IE8+) | 語義清晰,適合固定尺寸元素 |
absolute + calc() |
⚠️ 一般(IE9+) | 不推薦,既不方便也不通用 |
寬高不固定元素適用的方案
| 方案 | 兼容性 | 備註 |
|---|---|---|
absolute + transform |
✅ 較好(IE9+) | 最常用,推薦優先考慮 |
line-height |
✅ 非常好(IE6+) | 適合單行文字,有繼承問題需手動處理 |
writing-mode |
✅ 非常好(IE6+) | 實現和理解起來比較複雜,不推薦 |
<table> + text-align |
✅ 非常好(IE6+) | 結構語義不合理,適合郵件模板等場景 |
display: table-cell |
✅ 非常好(IE6+) | 替代表格結構,語義更合理 |
flex |
⚠️ 一般(IE10+) | 推薦使用,現代項目首選 |
flex + margin: auto |
⚠️ 一般(IE10+) | 更簡潔,但僅適合單元素居中 |
grid |
⚠️ 較差(IE11 部分支持) | 簡單強大,但需注意兼容性,不如 Flex 普遍 |
- 如果項目兼容性要求低,首選
flex + align/justify-center或absolute + transform方案 - 如果需要兼容 IE9 及以下瀏覽器,首選
absolute + 負 margin或table-cell方案
參考文章
- CSS實現水平垂直居中的10種方式劃重點,這是一道面試必考題,很多面試官都喜歡問這個問題,我就被問過好幾次了 要實現上圖 - 掘金
- 實現元素水平+垂直居中的方法(持續更新)1. 父元素:flex flex這個東西簡直就是一個神器... 這個時候子元素就 - 掘金
- 元素水平垂直居中常用方法彙總行內元素 line-height + text-align 行內塊狀元素 line-heig - 掘金
- 如何讓一個元素水平垂直居中?(代碼實例+方案總結) 超詳細!!!!在日常的開發中,我們經常會面對這樣一個問題:如何實現居 - 掘金
博客地址:https://github.com/wjw020206/blog