前端知库

怎样让一个元素水平垂直居中?

现在最常用的是 Flex 的 justify-content 加 align-items,或者 Grid 的 place-items: center,元素宽高未知也能居中。脱离文档流的元素用 absolute 配合 inset: 0 和 margin: auto,或者 top/left 50% 加 transform 往回移一半。

参考答案

简答

做一个弹窗或者空状态提示,要把一块内容放在容器正中间,现在首选 Flex 或 Grid。Flex 写法是父元素 display: flex,再加 justify-content: center 管水平、align-items: center 管垂直;Grid 更短,父元素 display: grid; place-items: center 一行就够。两种都不需要知道子元素的宽高。

如果元素是绝对定位的,比如盖在页面上的弹窗,有两种写法。一种是 position: absolute; inset: 0; margin: auto,但元素必须有确定的宽高。另一种是 top: 50%; left: 50%; transform: translate(-50%, -50%),先把左上角移到中心,再往回移自身宽高的一半,宽高不确定也能用。

只是让一行文字或行内元素水平居中,在父元素上写 text-align: center 就行;固定宽度的块元素水平居中,用 margin: 0 auto。

要注意,垂直居中需要父元素有高度。父元素高度由内容撑开时,内容本身就占满了,看不出居中效果,这时要给父元素设高度或 min-height。

Flex 和 Grid 的写法

下面两段代码效果相同,都能让 .child 在 .parent 里居中:

CSS
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
}

.parent-grid {
  display: grid;
  place-items: center;
  min-height: 300px;
}

Flex 里为什么 justify-content 管水平、align-items 管垂直?因为 Flex 默认的主轴是水平方向,justify-content 控制主轴,align-items 控制交叉轴。如果改成了 flex-direction: column,主轴变成垂直方向,两者管的方向就对调了。

Grid 的 place-items 是 align-items 和 justify-items 的简写,只写一个 center 就同时设置了两个方向。Grid 不受主轴方向影响,所以写起来更省心。

还有一种 Flex 写法:父元素只写 display: flex,子元素写 margin: auto。在 Flex 容器里,auto 外边距会吃掉所有剩余空间,四个方向都是 auto,元素就被挤到了正中间。

绝对定位元素怎么居中

弹窗、加载遮罩这类元素经常是绝对定位或固定定位的,它们脱离了文档流,父元素的 Flex 对它们不起作用。

CSS
.modal-known-size {
  position: fixed;
  inset: 0;
  width: 400px;
  height: 240px;
  margin: auto;
}

.modal-any-size {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

第一种为什么必须写宽高?inset: 0 让元素的四条边都贴着容器,这时如果没有宽高,元素会被拉伸到和容器一样大,谈不上居中。有了固定宽高,剩下的空间由 margin: auto 平均分到两边,元素就居中了。

第二种为什么要 transform?top: 50%; left: 50% 是把元素的左上角放到容器中心,元素整体偏右下。translate(-50%, -50%) 里的百分比是相对元素自己的宽高算的,往左上移一半,中心就对上了。这样不需要知道元素多大。

要注意,transform 的结果有时会落在半像素上,文字在某些屏幕上可能有点发虚。能用 Flex 或 Grid 的时候,优先用它们。

常见追问

行内元素或者一行文字怎么垂直居中?

单行文字可以让 line-height 等于容器高度,文字就会垂直居中,但只适合确定只有一行的情况,换行后行高会撑大。多行文字或者图标加文字,用 Flex 的 align-items: center 更可靠。

为什么 vertical-align: middle 在 div 上不起作用?

vertical-align 只对行内元素、行内块元素和表格单元格生效,它对齐的是元素在一行里的位置,不是在父容器里的位置。普通的块级 div 写了也没有效果。

Flex 和 Grid 居中有什么区别?

只居中一个元素时效果一样。区别在有多个子元素时:Flex 会把它们沿主轴排成一行再整体居中,Grid 默认把它们排成多行,每个都在自己的格子里居中。两者怎么选见《Flexbox 和 Grid 应该如何选择?》。