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(推荐)
.parent {
display: flex;
justify-content: center;
align-items: center;
}
优点:简洁、不需要知道子元素尺寸、响应式友好 缺点:几乎没有
方案二:Grid(推荐)
.parent {
display: grid;
place-items: center;
}
优点:代码最简洁 缺点:几乎没有
方案三:绝对定位 + transform
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
优点:不需要知道子元素尺寸
缺点:脱离文档流,父元素需要 position: relative
方案四:绝对定位 + 负 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(定宽高)
.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 + 伪元素
.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 种方案(见上表)。面试中推荐先说 Flex 和 Grid(现代方案),再提 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?
答案:
不需要知道子元素尺寸的方案有:
- Flex —
justify-content: center+align-items: center - Grid —
place-items: center - 绝对定位 + transform —
top: 50%; left: 50%; transform: translate(-50%, -50%)
不可用:margin: auto(块级水平居中需要定宽)、负 margin(需要定宽高)。
Q3: margin: 0 auto 为什么能实现水平居中?
答案:
当块级元素设置了确定的 width 并且 margin-left 和 margin-right 都为 auto 时,浏览器会将剩余水平空间平均分配给左右 margin,从而实现水平居中。
条件:
- 元素必须是块级元素
- 必须有确定的宽度(不能是
auto) - 宽度小于父元素
注意:margin: auto 在垂直方向上不能实现居中(值为 0),除非在绝对定位 + inset: 0 的场景下。
Q4: 绝对定位 + margin: auto 为什么能实现垂直居中?
答案:
.child {
position: absolute;
inset: 0; /* 上下左右都为 0 */
margin: auto;
width: 200px;
height: 100px;
}
原理:绝对定位 + inset: 0 让元素想要占满父容器。但 width 和 height 限制了实际大小。此时上下左右的 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 只对以下元素生效:
inline元素inline-block元素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 时:
- 容器内只有一个行盒,高度等于容器高度
- 行内内容在行盒中默认垂直居中分布
- 因此文字看起来垂直居中了
限制:
- 只适用于单行文本
- 多行文本会导致行与行之间间距过大
- 不适用于块级子元素