前言
感觉css开发中,含金量最高的地方就是布局,把元素摆放在特定的位置;而像设置元素宽高,文本对齐,内外边距,阴影渐变,字体与背景色, 内容溢出显示省略号等这些都是so easy的事情。让容器中的元素垂直水平居中,是日常开发一个高频场景。比面试中问到的BFC/IFC, 如何清除浮动要实用的多(笔者做前端开发的这些年,基本上没有用到过浮动)。因此决定把css实现水平垂直居中方式, 整理一下,以备不时之需。现在我们进入主题。
常见的水平垂直居中方法
为了减少文中的重复代码片段,我们先把每种水平垂直居中对齐的公共样式写一下,其中.base-box
和.base-item
分别是容器和需要对齐元素的外观样式。有读者可能会对下面的css代码产生疑问,说你这种写法是Less/Sass
才有的嵌套写法,不是原生css的写法。这里要说明一下,最新版的浏览器已经支持一些原来的Less/Sass
才支持的语法,不了解的话请参考此文。
.base-box {
width: 400px;
height: 200px;
background-color: greenyellow;
&+& {
margin-top: 10px;
}
.base-item {
width: auto;
height: 100px;
background-color: red;
}
}
方案一 flex布局
这种方案可以细分两个版本,一种是在flex容器上设置主轴和交叉轴水平垂直居中属性,另外一种是在flex项目上,设置自身的水平垂直居中属性。
<link rel="stylesheet" href="./base.css" />
<style>
.flex-center-1 {
display: flex;
justify-content: center;
align-items: center;
}
.flex-center-2 {
display: flex;
justify-content: center;
.item {
align-self: center;
}
}
</style>
<div class="base-box flex-center-1">
<div class="base-item"></div>
</div>
<div class="base-box flex-center-2">
<div class="base-item item"></div>
</div>
这种对齐方式应用最广, 因为对子元素的宽高没有限制,而且浏览器兼容性也比较好。
效果如下:
方案二 绝对/相对定位+transform方案
先将子元素设置为相对或绝对定位,再将子元素的位置设定为父容器的中心点(即top: 50%
和left: 50%
),这会使子元素的左上角相对于父容器的中心进行定位。
为什么将子元素设置成相对或绝对定位,再设置top: 50%
和left: 50%
,都能让子元素的左上角处于父容器的中心点。这是因为采用相对定位时,top和left设置为百分比,这个百分比是相对于父元素的宽高而言的。采用绝对定位时,由于给父元素设置了相对定位,这是子元素的top和left设置的百分比,也是根据父元素的宽高计算的。如下图所示:
所以这两种情形,都能使用同样的移动效果。接下来通过transform: translate(-50%, -50%)
将子元素向左和向上平移自身宽高的一半(translate中的百分比是根据自身的宽高来计算的),这样就能使子元素的中心点与父容器的中心点重合,从而实现水平和垂直居中。
<link rel="stylesheet" href="./base.css" />
<style>
.transform-center-1 {
position: relative;
.item-1 {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.transform-center-2 {
.item-2 {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
</style>
<div class="base-box transform-center-1">
<div class="base-item item-1"></div>
</div>
<div class="base-box transform-center-2">
<div class="base-item item-2"></div>
</div>
这种方式不需要预先知道子元素的具体尺寸,因此适用于未知宽高或者动态变化尺寸的元素居中问题。同时,由于transform
不会影响布局流(不影响其他元素的位置),所以是一种性能较好的居中解决方案。
方案三 table-cell方案
当一个元素的display
属性被设置为table-cell
时,该元素将会表现出如同<td>
单元格一样的行为特征,设置vertical-align: middle
在具有display: table-cell
的元素上,可以使该元素内的内容在垂直方向上居中对齐。水平居中,可以使用给父元素设置text-align:center
属性, 子元素设置display:inline-block;
。在CSS中,给父元素添加text-align: center;
属性意味着父元素内部的行内内容或行内级元素会被水平居中对齐。当子元素设置了display: inline-block;
属性 ,子元素会变成行内块元素,它遵循行内元素的对齐规则,所以当父元素设置了text-align: center;
时,子元素就会按照水平居中规则显示。
<link rel="stylesheet" href="./base.css" />
<style>
.table-cell-box {
display: table-cell;
text-align:center;
vertical-align: middle;
.item {
display: inline-block;
}
}
</style>
<div class="base-box table-cell-box">
<div class="base-item item"></div>
</div>
通过这样的方式,即使子元素内容大小未知,也可以实现内容在容器内的灵活居中对齐。这种方法尤其适用于兼容性要求较高的场景,在 Flexbox 或 Grid 布局还未普及之前的浏览器环境下是一种常用的居中解决方案。
方案四 table布局
这种方案很好理解,设置单元格中内容垂直居中,子元素就会表现为垂直居中,接着设置单元格内容水平居中,将子元素设为内联块元素,子元素在水平方向上就会居中。这样就实现了垂直水平居中。此种方案的缺点显而易见,dom层级过多,但优点是不需要关注子元素的尺寸。
<link rel="stylesheet" href="./base.css" />
<style>
.table-box {
vertical-align: middle;
text-align: center;
.item {
display: inline-block;
}
}
</style>
<table>
<tr>
<td class="base-box table-box">
<div class="base-item item"></div>
</td>
</tr>
</table>
方案五 Grid布局
CSS Grid布局是一种现代布局模式,它提供了一套强大的二维布局系统,使得在网页设计中更容易实现元素的复杂排列,包括轻松地实现容器内单个或多个项目的水平和垂直居中。这里的.grid-box-1
是需要进行居中布局的容器,.item
是需要居中的子元素。通过display: grid
将容器转换为网格容器,而align-items: center
和justify-items: center
两个属性会让容器内的所有直接子元素都将自动地沿行轴(即水平方向)和列轴(即垂直方向)居中对齐。还有一种方式就是单独给子元素设置水平和垂直居中。
<link rel="stylesheet" href="./base.css" />
<style>
.grid-box-1 {
display: grid;
align-items: center; /* 沿垂直方向(列轴)居中 */
justify-items: center; /* 沿水平方向(行轴)居中 */
}
.grid-box-2 {
display: grid;
.item {
justify-self: center; /* 单独控制水平居中 */
align-self: center; /* 单独控制垂直居中 */
}
}
</style>
<div class="base-box grid-box-1">
<div class="base-item item"></div>
</div>
<div class="base-box grid-box-2">
<div class="base-item item"></div>
</div>
grid布局和flex布局十分相像,无论子元素尺寸如何变化,都能让其保持在容器中心位置。但移动端浏览器对Grid布局的支持性不如flex布局那么好。
方案六 writing-mode
CSS的writing-mode
属性主要用于改变文本的方向和布局流,可以与其它CSS属性组合使用,间接实现垂直居中效果。当父元素writing-mode
设为垂直方向时,原本的水平方向属性(如text-align
)将会影响子元素垂直方向的对齐。看起来的效果是子元素在父容器中垂直居中。接着在子元素中在放置一个后代元素.content
,设置这个content为内联元素,在子元素中通过文本居中属性,让后代元素水平居中。从而实现后代元素水平垂直的效果。这种方式实现水平居中不太优雅,需要额外添加后代元素,层级较多,好处是可以不必知道后代元素的尺寸,让后代元素居中。
<link rel="stylesheet" href="./base.css" />
<style>
.writing-mode-box {
/* 竖排从右到左 */
writing-mode: vertical-lr;
text-align: center;
.item {
display: inline-block;
/* 默认的从左到右横排 */
writing-mode: horizontal-tb;
text-align: center;
height: auto;
width: 100%;
.content {
display: inline-block;
text-align: left;
background-color: green;
}
}
}
</style>
<div class="base-box writing-mode-box">
<div class="base-item item">
<div class="content">1111</div>
</div>
</div>
方案七 绝对定位+margin:auto
父元素设置相对定位,子元素设置绝对定位,同时设置子元素的top
,bottom
,left
,right
位置偏移为0。这使得子元素的边缘与父元素四个方向的边缘相接触,形成一个覆盖整个父元素的盒子。当子元素设置了四个边缘位置偏移为0之后,其margin
属性中的auto
值就有了可以参考的上下文——即元素自身的尺寸与父元素之间的差距。在水平方向上,margin-left
和margin-right
同时设为auto
时,浏览器会平均分配元素宽度之外的剩余空间,从而使元素水平居中。在垂直方向上,若元素具有确定高度且同时设置了top
和bottom
为0
,margin-top
和margin-bottom
为auto
的话,根据CSS规范,上下边距值会被设置为相同的正值,能够将子元素推至上下边缘正中间,从而实现垂直居中。
<style>
.absolute-margin-auto {
position: relative;
.item {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
}
}
</style>
<div class="base-box absolute-margin-auto">
<div class="base-item item"></div>
</div>
这种对齐方式需要给子元素设置固定的宽高。因为margin: auto
在水平或垂直方向上的居中对齐要求子元素的宽高不能为auto
。适用范围不如前面三种居中对齐方式那么广泛。
方案八 绝对定位+负margin
此种方式和transform方式比较相似。不同的是transform方式是让浏览器自动计算水平和垂直方向上的具体偏移值,这种方式要自己计算水平垂直方向上的偏移值。 此外需要知道父容器的宽和高,自身也需要设置固定的宽高,使用起来限制比较大。
<link rel="stylesheet" href="./base.css" />
<style>
.absolute-negative-margin {
position: relative;
.item {
position: absolute;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -50px;
}
}
</style>
<div class="base-box absolute-negative-margin">
<div class="base-item item"></div>
</div>
方案九 绝对定位+calc
当知道容器的宽度和高度时,可以通过父相子绝定位,结合calc()
计算出元素的正确偏移量来实现居中。这种方式是把绝对定位+负margin布局方式偏移设置两步合并成一步,此种方式需要知道子元素的尺寸,以及给父元素设置固定尺寸,使用起来有一定的限制性。
<link rel="stylesheet" href="./base.css" />
<style>
.absolute-calc-box {
position: relative;
.item {
position: absolute;
left: calc(50% - 100px); /* 减去的宽度为子元素自身宽度的一半 */
top: calc(50% - 50px); /* 减去的高度为子元素自身高度的一半 */
}
}
</style>
<div class="base-box absolute-calc-box">
<div class="base-item item"></div>
</div>
方案十 line-height方案
在CSS中,当父元素设置了固定的高度(height
)和行高(line-height
),并且这两个值相等时,就可以实现单行文本内容的垂直居中对齐。将子元素设置为内联块级元素。子元素的表现效果和单行文本一样,再给父容器设置文本水平居中,子元素就能水平居中。这种方法的局限性比较大,需要知道父元素的高度,还有只对单行内容有效。
<link rel="stylesheet" href="./base.css" />
<style>
.single-box {
line-height: 200px;
text-align: center;
.item {
display: inline-block;
/* 显式设置子元素的行高与自身高度相等 */
line-height: 100px;
}
}
</style>
<div class="base-box single-box">
<div class="base-item item">11</div>
</div>
方案十一 伪元素方案
当有多个行内块级元素(display: inline-block
),并且每个元素都设置了vertical-align: middle
时,所有元素的垂直对齐是相对于它们所在行框(line box)的基线(baseline)进行的 ,如果各个元素的高度不同,它们各自的“中间”位置可能会有所差异,但都会尽量接近于行框的垂直中点,这个中点是基于行框内所有字体的 (x 字母高度)平均计算得出的。在实际应用中,通过在父元素中创建一个伪元素,并设置其height: 100%
和display: inline-block
,这样它会占据父元素的整个高度。接着给每个子元素设置vertical-align: middle
,然后就可以通过vertical-align: middle
将实际内容元素与这个伪元素垂直对齐,从而达到父容器内各个子元素垂直居中的效果。水平居中比较简单。这种方案可以实现单行多个不同高度的垂直居中。不需要知道每个子元素的尺寸。缺点就是需要额外创建一个伪元素,不如其它对齐方案优雅。
<link rel="stylesheet" href="./base.css" />
<style>
.single-box {
text-align: center;
&::before {
content: "";
width: 0;
height: 100%;
display: inline-block;
vertical-align: middle;
}
.item {
display: inline-block;
width: 50px;
vertical-align: middle;
&:nth-of-type(1) {
height: 40px;
}
&:nth-of-type(2) {
height: 100px;
}
&:nth-of-type(3) {
height: 80px;
}
}
}
</style>
<div class="base-box pseudo-box">
<div class="base-item item">11</div>
<div class="base-item item">22</div>
<div class="base-item item">33</div>
</div>
怎么选?
学习了这11种水平垂直居中方案,使用的时候该怎么选呢。从通用性,易用性,兼容性角度来讲,优先要考虑对子元素宽高没有限制的对齐方式,可按如下顺序选择flex
> 相对/绝对定位+transform
> table-cell
> grid,
,write-mode
和table
这两种方案不推荐使用,一个太偏门,一个不优雅。 中策可供选择的对齐方案是绝对定位+margin:auto
> 绝对定位+calc
> 绝对定位+负margin
。line-height
和伪元素
对齐方案,可以作为单行内联块级元素对齐的备选方案。
最后
掌握了文章的水平垂直居中方案,如果你仅想单独实现水平或垂直居中效果,可以把这11个示例中的另一半用不到的居中内容移除。你们没有时间整理这些高频使用的知识点,我来帮你们整理,你只需收藏一下,需要用的时候直接复制示例中的代码片段。每个示例我都验证过效果了,经得起实践的考验。我所知道的css水平垂直居中对齐方案就是这11种,如果你还知道别的方案,欢迎补充。我们留言区见。