动态

详情 返回 返回

CSS專題之水平垂直居中 - 动态 详情

前言

石匠敲擊石頭的第 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>

image.png

固定寬高元素

absolute + 負 margin

.container {
  /* 其它的基礎樣式... */
  position: relative;
}

.box {
  /* 其它的基礎樣式... */
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -50px;
  margin-top: -50px;
}

該方案的原理非常簡單,可以分為兩步來看:

  1. 先通過絕對定位top: 50%left: 50% 使元素的左上角定位在 .container 容器元素的中心位置

    image.png

  2. 再通過 margin-topmargin-left 設置為負值,具體值為元素寬度和高度的一半,例如這裏元素的寬高都是 100px,所以一半就是 50px

    image.png

    最終的效果如下

    image.png

在線查看效果

✅ 優點: 兼容性好,適用於 IE 等老版本瀏覽器。

⚠️ 缺點:

  • 需要提前知道元素大小,並且需要手動計算元素大小的一半
  • 每次修改元素大小都需要同步修改 margin

absolute + margin: auto

.container {
  /* 其它的基礎樣式... */
  position: relative;
}

.box {
  /* 其它的基礎樣式... */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}

該方案和前一個方案最終效果是一樣,該方案的步驟如下:

  1. 通過設置絕對定位 top:0; bottom:0; left:0; right:0;,讓瀏覽器知道元素被限制”在父容器內四邊,這樣有了一個明確的空間範圍
  2. 再通過設置 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;
}

該方案的實現步驟如下:

  1. 首先給 .container 容器設置一個與高度相同的行高,例如這裏容器的高度為 300px,所以設置 line-height: 300px,並給容器設置 text-align: center; 水平居中對齊

    image.png

  2. 然後再給 .box 元素設置為行內塊(inline-block)元素,並設置 vertical-align: middle; 垂直居中對齊

    image.png

  3. 居中效果有了,但是文字卻不見了,因為 .container 容器的 text-alignline-height 默認是會被繼承給 .box 元素,這時我們需要通過 line-height: initialtext-align: initial 重置為初始值

    image.png

在線查看效果

✅ 優點: 無需提前知道元素大小,修改元素大小不需要同步修改相關的值

⚠️ 缺點: 需要重置內部元素的文字樣式

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 讓元素文字水平方向顯示

該方案實現的步驟如下:

  1. 首先將 .container 容器的文字顯示方向調整為垂直方向,並設置文字水平居中對齊,用來實現垂直居中

    image.png

  2. 添加一個 .inner 包裝元素,設置為行內塊(inline-block)元素,並將寬度設置為 100%,並設置文字顯示方向為水平方向,此時 .container 容器的 text-align: center; 被繼承,變成了水平居中

    image.png

  3. 最後將 .inner 包裝元素內部的 .box 元素調整為行內塊(inline-block)元素,並重置繼承的 text-align 屬性的值為初始值

    image.png

在線查看效果

✅ 優點:

  • 兼容性好,適用於 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-centerabsolute + transform 方案
  • 如果需要兼容 IE9 及以下瀏覽器,首選 absolute + 負 margintable-cell 方案

參考文章

  • CSS實現水平垂直居中的10種方式劃重點,這是一道面試必考題,很多面試官都喜歡問這個問題,我就被問過好幾次了 要實現上圖 - 掘金
  • 實現元素水平+垂直居中的方法(持續更新)1. 父元素:flex flex這個東西簡直就是一個神器... 這個時候子元素就 - 掘金
  • 元素水平垂直居中常用方法彙總行內元素 line-height + text-align 行內塊狀元素 line-heig - 掘金
  • 如何讓一個元素水平垂直居中?(代碼實例+方案總結) 超詳細!!!!在日常的開發中,我們經常會面對這樣一個問題:如何實現居 - 掘金

博客地址:https://github.com/wjw020206/blog

user avatar Leesz 头像 zaotalk 头像 nihaojob 头像 freeman_tian 头像 qingzhan 头像 kobe_fans_zxc 头像 aqiongbei 头像 thosefree 头像 chongdianqishi 头像 leexiaohui1997 头像 longlong688 头像 inslog 头像
点赞 160 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.