简短的回答
要让 div 在父元素中水平和垂直同时居中,就把父元素设为 grid,再让它的内容居中:
.parent {
display: grid;
place-items: center;
min-height: 200px; /* the parent needs room to center in */
}
子元素多大都可以,而且子元素本身什么都不用写。下面把六种方法放在一起对比。每个盒子渲染后都会测量自己,并打印出它的中心离父元素中心有多远:
六种方法在两个方向上都报告 0px(舞台的 1px 边框四边相等,所以不会让中心偏移)。改一下某个盒子的宽度或文字再运行一次:不依赖固定尺寸的方法仍然是 0。
该用哪种方法
| 方法 | 居中方向 | 子元素需要固定尺寸吗? | 最适合 |
|---|---|---|---|
Grid place-items: center | 两个方向 | 不需要 | 默认选择:盒子里只有一个子元素 |
Flexbox justify-content + align-items | 两个方向 | 不需要 | 一行或一列项目,作为一组居中 |
flex 或 grid 父元素中的 margin: auto | 两个方向 | 不需要 | 让一个项目居中,而它的兄弟元素按别的方式排列 |
margin: 0 auto | 仅水平 | 需要 width 或 max-width | 正常流中的页面容器、文章、表单 |
Absolute + translate(-50%, -50%) | 两个方向 | 不需要 | 盖在其他内容上面的遮罩、徽标和弹窗 |
Absolute + inset: 0; margin: auto | 两个方向 | 需要,宽度和高度 | 固定尺寸的对话框 |
块元素上的 align-content: center | 垂直 | 不需要 | 不改变父元素 display 的垂直居中 |
方法 1:flexbox
Flexbox 用两个属性在两个轴上居中。justify-content 负责主轴(在一行中就是水平方向),align-items 负责交叉轴:
有多个子元素时,flexbox 会把它们作为一组居中,并保持排成一行。这正是它胜过 grid 的地方:grid 会把三个项目叠成居中的一列。justify-content 页面讲解了所有对齐值。
方法 2:grid
place-items: center 是 align-items: center 加 justify-items: center 的简写。在只有一个子元素的 grid 容器上,它会让这个子元素在两个方向上都居中:
用 min-height 而不是 height,这样卡片高于 180px 时父元素会跟着变高,卡片不会溢出。
方法 3:margin: 0 auto(水平居中)
宽度小于容器的块元素,可以用自动的左右外边距实现水平居中。浏览器会把剩余空间平均分给两边:
第二个盒子占满了整行宽度,没有剩余空间,所以什么都没有移动。这就是 margin: 0 auto“不起作用”最常见的原因。另外它在正常流中只能水平居中,垂直方向的 auto 外边距在那里会变成 0。不过在 flex 或 grid 父元素中,margin: auto 会在两个方向上都居中,也就是上面对比中的第三个盒子。
方法 4:absolute 定位加 transform
当元素必须盖在其他内容上面时(照片上的徽标、页面上的弹窗),把它绝对定位到 50% 的位置,再往回拉自身尺寸的一半:
top: 50%; left: 50% 把元素的左上角放到中心点。translate() 中的百分比是相对元素自身尺寸的,所以无论宽高是多少,-50% 都会把它往回移动自身宽高的一半。父元素必须是定位元素(position: relative),否则元素会相对整个页面居中。定位的内容见 position 页面。
已知尺寸的元素还有一种写法:position: absolute; inset: 0; margin: auto;,再加上 width 和 height。自动外边距会在四个方向上平分空间。
方法 5:普通块元素上的 align-content
align-content: center 现在也能用在普通的块容器上,不再只限于 flex 和 grid 容器。它让内容垂直居中,而不改变子元素的布局方式:
.parent {
min-height: 200px;
align-content: center; /* vertical centering, still display: block */
}
.child {
max-width: 300px;
margin-inline: auto; /* horizontal centering */
}
当前版本的 Chrome、Firefox 和 Safari 都支持它。旧浏览器会忽略它,所以如果必须兼容旧浏览器,就用 grid。
在整个屏幕中居中
要让对话框在视口中居中,而且不受滚动影响,就把一个固定定位的全屏图层和 grid 结合起来:
.overlay {
position: fixed;
inset: 0; /* covers the viewport */
display: grid;
place-items: center;
background: rgb(0 0 0 / 50%);
}
要让整个页面的内容垂直居中,在父元素上用 min-height: 100dvh,而不是 100vh:在手机上,100vh 包含了浏览器工具栏后面的区域,所以“中心”会偏低。
让文字居中是另一回事
上面的方法都是让一个盒子居中。要让盒子里的文字居中,就在盒子上用 text-align: center,详见 HTML 文字居中页面。很多时候两者都需要:用 grid 让卡片居中,再用 text-align 让卡片里的每一行居中。
常见错误
- 父元素没有高度。 垂直居中需要剩余空间,而高度随内容收缩的父元素没有剩余空间。
- 在占满整行的块元素上用
margin: 0 auto。 先给它设置width或max-width。 - 在正常流中用
margin: auto垂直居中。 正常流中垂直方向的自动外边距是 0,请用 flex 或 grid。 - 绝对定位居中,但父元素不是定位元素。 元素会在页面中居中,而不是在盒子里。
- 把
align-items: center写在子元素上。 对齐属性要写在父元素(flex 或 grid 容器)上,margin: auto和align-self除外。 - 用
text-align: center让块元素居中。 它居中的是行内内容(文字、图片、inline-block 子元素),而不是块级子元素。
常见问题
如何让 div 水平和垂直同时居中?
把父元素设为 grid 并让内容居中:.parent { display: grid; place-items: center; }。flexbox 的写法是 display: flex; justify-content: center; align-items: center;。无论哪种写法,父元素的高度都要比 div 高。
如何只让 div 水平居中?
给它设置宽度和自动的左右外边距:.box { width: 300px; margin: 0 auto; }(响应式的块可以用 max-width)。margin-inline: auto 是同一件事的逻辑属性写法。
为什么 margin: 0 auto 不能让我的 div 居中?
这个 div 的宽度并不比容器小,所以没有可以分配的剩余空间(块元素默认占满整行宽度)。设置 width 或 max-width 即可。它对行内元素也不起作用,在正常流中也永远不会垂直居中。
为什么我的 div 不能垂直居中?
父元素的高度只等于内容的高度,没有多余的空间可以居中。给父元素设置一个高度(或 min-height),再用 grid 或 flexbox 居中。
让 div 居中最简单的方法是什么?
在父元素上写 display: grid; place-items: center;:两条声明,两个方向,子元素多大都行。如果父元素还要把其他项目排成一行,就用 flexbox。
如何让 div 里的文字居中?
在 div 上用 text-align: center,它作用于文字和行内内容。让 div 本身居中和让 div 里的文字居中是两件不同的事。