Skip to content

元素垂直居中

925字约3分钟

2022-04-13

提问

  • 在 某某场景下,如何让某某元素垂直居中?
  • 有哪些方式可以实现元素的垂直居中?

设立一个场景:在一个宽高不固定的容器中,实现一个宽高不固定的内容盒子,并垂直水平居中。

<!-- 假设 warpper、container 宽高不固定 实现container相对于wrapper垂直水平居中-->
<div class="wrapper">
  <div class="container"></div>
</div>

方法一: 使用 flex 布局

.wrapper {
  display: flex;
}
.container {
  margin: auto;
}

适用于支持 flex布局的浏览器(IE11以上,其他现代浏览器)。这里是利用flex弹性布局的特性,弹性容器改变了其子元素填充可用空间的方式,子元素默认从容器左上角开始排列,在不设置宽高时,子元素填充空间由flex声明,默认值为0 1 auto,即 flex-grow: 0;flex-shrink: 1;flex-basis: auto; 其中 flex-basis定义了子元素的宽和高的尺寸大小,auto值表示自动尺寸,根据子元素内容计算宽高,在子元素上设置margin: auto,这是利用auto平均分配水平或垂直方向上的额外的空间,从而达到目的。(此方法实现的结果是“真正的”垂直水平居中)

或者

.wrapper {
  display: flex;
  justify-content: center;
  align-content: center;
}

方法二: 使用 table 布局

.wrapper {
  display: table-cell;
  vertical-align: middle;
}
.container {
  margin: auto;
}

利用的是table布局的特性,不过该方法有个缺点就是,display: table-cell元素的宽高设置百分比数值是“无效的”,原因是父元素非table元素或display: table元素,display: table-cell元素的宽高百分比数字是相对于table计算的。

方法三: position + transform

.wrapper {
  position: relative;
}
.container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

该方法与前面两个方法的作用机理有很大的不同,首先第一点是container脱离了文档流, 并且container自身的宽高发生了坍塌,在不设置宽高属性下,尺寸由内容撑开, container相对wrapper元素进行绝对定位,水平方向与垂直方向上, container的左上角顶点偏移到wrapper中点,containertransform是相对于自身的, translate(-50%, -50%)相对于自身,将左上角顶点做左上偏移自身的一半,从而实现了目的。

有一些面试者给出了container元素上设置margin-left: -50%; margin-top: -50%的答案,然而,margin的百分比值,是相对于其父元素计算的。

方法四: 使用 行内块元素

.wrapper {
  text-align: center;
}
.wrapper:after {
  content: '';
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}
.container {
  display: inline-block;
  vertical-align: middle;
  text-align: left;
}

该方法实现的垂直水平居中其实是一个近似垂直水平居中,兼容IE7以上的浏览器。 水平方向上.wrapper设置text-align: center;实现了水平居中;垂直方向上, 给定container声明行内块元素,并vertical-align: middle,但由于container高度不确定, 无法声明具体的行高,所以借助了父元素的伪类元素,创建了一个宽度为0高度为100%的行内块元素, 从而使container元素在垂直方向上实现了居中。 但由于vertical-align: middle是元素的中线与字符X的中心点对齐,大多数字体设计字体的中心点偏下, 也导致了实现的垂直居中并不是绝对的垂直居中。而要实现绝对的垂直居中,需要添加一下属性:

.wrapper {
  font-size: 0;
  white-space: nowrap;
}
.container {
  font-size: 14px; /* 重置回默认字体大小 */
  white-space: normal;
}