跳到主要内容

CSS 居中方案

问题

如何实现水平居中、垂直居中、水平垂直居中?各方案的适用场景和优缺点是什么?

答案

水平居中

1. 行内元素 / 文本 — text-align

.parent {
text-align: center;
}
/* 适用于 inline、inline-block、inline-flex、inline-grid 元素 */

2. 块级元素(定宽) — margin: 0 auto

.child {
width: 200px; /* 必须有确定宽度 */
margin: 0 auto;
}

3. Flex

.parent {
display: flex;
justify-content: center;
}

4. Grid

.parent {
display: grid;
justify-items: center;
}

5. 绝对定位 + transform

.parent { position: relative; }
.child {
position: absolute;
left: 50%;
transform: translateX(-50%);
}

垂直居中

1. 单行文本 — line-height

.box {
height: 60px;
line-height: 60px; /* line-height = height */
}

2. Flex

.parent {
display: flex;
align-items: center;
}

3. Grid

.parent {
display: grid;
align-items: center;
}

4. 绝对定位 + transform

.parent { position: relative; }
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}

5. vertical-align(表格布局)

.parent {
display: table-cell;
vertical-align: middle;
}

水平垂直居中(重点)

这是面试最常问的问题。以下方案按推荐程度排列:

方案一:Flex(推荐)

Flex 居中
.parent {
display: flex;
justify-content: center;
align-items: center;
}

优点:简洁、不需要知道子元素尺寸、响应式友好 缺点:几乎没有

方案二:Grid(推荐)

Grid 居中 — 最简写法
.parent {
display: grid;
place-items: center;
}

优点:代码最简洁 缺点:几乎没有

方案三:绝对定位 + transform

绝对定位 + transform
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

优点:不需要知道子元素尺寸 缺点:脱离文档流,父元素需要 position: relative

方案四:绝对定位 + 负 margin(定宽高)

绝对定位 + 负 margin
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 100px;
margin-top: -50px; /* -height/2 */
margin-left: -100px; /* -width/2 */
}

优点:兼容性极好 缺点:必须知道子元素宽高

方案五:绝对定位 + margin: auto(定宽高)

绝对定位 + margin auto
.parent {
position: relative;
}
.child {
position: absolute;
inset: 0; /* top:0; right:0; bottom:0; left:0 */
margin: auto;
width: 200px;
height: 100px;
}

优点:不需要 transform,性能好 缺点:必须知道子元素宽高

方案六:vertical-align + 伪元素

vertical-align 方案
.parent {
text-align: center;
}
.parent::before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.child {
display: inline-block;
vertical-align: middle;
}

优点:不脱离文档流 缺点:代码繁琐,需要处理空白字符

方案对比总表

方案是否需要知道尺寸是否脱离文档流代码量推荐度
Flex⭐⭐⭐
Grid place-items⭐⭐⭐
absolute + transform⭐⭐⭐⭐
absolute + 负 margin⭐⭐
absolute + margin: auto⭐⭐⭐⭐
vertical-align + 伪元素⭐⭐⭐
table-cell⭐⭐

常见面试问题

Q1: 水平垂直居中有几种方法?

答案

常见 6 种方案(见上表)。面试中推荐先说 FlexGrid(现代方案),再提 absolute + transform(传统方案),最后补充 absolute + margin 等。

重点记住:

/* 最推荐 */
.flex { display: flex; justify-content: center; align-items: center; }
.grid { display: grid; place-items: center; }

/* 经典方案 */
.abs { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }

Q2: 如何居中一个不定宽高的 div?

答案

不需要知道子元素尺寸的方案有:

  1. Flexjustify-content: center + align-items: center
  2. Gridplace-items: center
  3. 绝对定位 + transformtop: 50%; left: 50%; transform: translate(-50%, -50%)

不可用margin: auto(块级水平居中需要定宽)、负 margin(需要定宽高)。

Q3: margin: 0 auto 为什么能实现水平居中?

答案

当块级元素设置了确定的 width 并且 margin-leftmargin-right 都为 auto 时,浏览器会将剩余水平空间平均分配给左右 margin,从而实现水平居中。

条件:

  1. 元素必须是块级元素
  2. 必须有确定的宽度(不能是 auto
  3. 宽度小于父元素

注意:margin: auto 在垂直方向上不能实现居中(值为 0),除非在绝对定位 + inset: 0 的场景下。

Q4: 绝对定位 + margin: auto 为什么能实现垂直居中?

答案

.child {
position: absolute;
inset: 0; /* 上下左右都为 0 */
margin: auto;
width: 200px;
height: 100px;
}

原理:绝对定位 + inset: 0 让元素想要占满父容器。但 widthheight 限制了实际大小。此时上下左右的 margin: auto 会收到剩余空间,浏览器会将其均分,从而实现水平和垂直居中。

这是绝对定位下 margin: auto 的特殊行为(正常流中垂直方向 margin: auto 为 0)。

Q5: transform: translate(-50%, -50%) 的百分比相对于谁?

答案

translate 的百分比相对于元素自身的宽高:

  • translateX(-50%) = 向左移动自身宽度的一半
  • translateY(-50%) = 向上移动自身高度的一半

配合 top: 50%; left: 50%(相对父元素),两者结合实现精确居中。

这与 margin 百分比(相对父元素宽度)、padding 百分比(相对父元素宽度)不同。

Q6: vertical-align: middle 为什么有时不生效?

答案

vertical-align 只对以下元素生效:

  1. inline 元素
  2. inline-block 元素
  3. table-cell 元素

块级元素完全无效。而且 vertical-align: middle 是将元素的中点与父元素 baseline + x-height/2 的位置对齐,不是容器的正中间。

要用 vertical-align 实现真正的垂直居中,需要配合 display: table-cell 或辅助伪元素:

/* table-cell 方案 */
.parent {
display: table-cell;
vertical-align: middle; /* 在 table-cell 中表现为垂直居中 */
height: 300px;
}

Q7: 如何让图片在容器中水平垂直居中?

答案

图片是行内替换元素,方案选择多:

/* 方案一:Flex(推荐) */
.container {
display: flex;
justify-content: center;
align-items: center;
}

/* 方案二:text-align + line-height(固定高度) */
.container {
text-align: center;
line-height: 300px; /* = container height */
}
.container img {
vertical-align: middle;
}

/* 方案三:object-fit(让图片同时适配容器) */
.container {
display: flex;
justify-content: center;
align-items: center;
}
.container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}

Q8: line-height 实现垂直居中的原理是什么?

答案

line-height 定义了行盒的高度。当 line-height 等于容器 height 时:

  1. 容器内只有一个行盒,高度等于容器高度
  2. 行内内容在行盒中默认垂直居中分布
  3. 因此文字看起来垂直居中了

限制:

  • 只适用于单行文本
  • 多行文本会导致行与行之间间距过大
  • 不适用于块级子元素

相关链接