比较全面的水平垂直居中方案。水平垂直居中问题大体分为两类,一类目标元素是行内元素,一类目标元素是块级元素(其中,块级元素又包括定宽高和不定宽高)。

1.水平居中方案

1.1 行内元素水平居中
把该行内元素包裹在一个块级父元素中,之后设置父元素:

.parent{
    text-align:center
}

1.2 块级元素水平居中
设置该元素:

div{
    width: 100px;  /* 注意宽度一定要给出 */
    margin: 0 auto; /* auto 是必须的 */
}

1.3 多个块级元素水平居中

  • 转换为行内元素。设置目标块级元素 display:inline-block,之后设置父元素:
.parent{
    text-align:center
}
  • 利用弹性盒子。设置父元素:
.parent{
    display:flex;
    justify-content: center;
}

2.垂直居中方案

2.1 块级父元素高度已知,行内子元素为单行

设置父元素:

.parent{
    /* 设置父元素的高度等于行高 */
    height:100px;
    line-height:100px;
}

Tip):这里的 line-height 最终是通过继承作用在子元素上的,所以也可以直接设置子元素为 line-height:100px

2.2 块级父元素高度已知,行内子元素为多行

设置父元素:

.parent{
    display:table-cell;
    vertical-align:middle;
    height:100px;
}

Tip:注意父元素得有高度,否则默认高度由子元素撑起,就没有垂直居中的说法了。

2.3 块级父元素高度未设置,子元素为行内或块级

设置父元素:

.parent{
    padding-top:10px;
    padding-bottom:10px;
}

2.4 块级子元素高度已知

设置父元素:

.parent{
    position:relative;
}

设置子元素:

div{
    position:absolute;
    top: 50%;
    height: 100px;
    margin-top: -50px;
}
/* 或者直接 */
div{
    position:absolute;
    top: calc(50% - 50px);
    height: 100px;   
}

Tip:原理是绝对定位。top:50% 确保了子元素位于父元素 1/2 分割线以下,margin-top: -50px代表子元素在这个基础上上移自身的一半高度,此时子元素与父元素中线重合,实现垂直居中。

2.5 块级子元素高度未知

虽然我们不知道子元素高度,但可以确定必定是在 top:50% 的基础上,上移自身的一半高度,这里可以改用 transform: translateY(-50%);

div{
    position:absolute;
    top: 50%;
    height: 100px;
    transfrom: translateY(-50%);
}

3.水平垂直居中方案

3.1 已知高度和宽度的元素

  • 方法一:

设置父元素:

.parent{
    position: relative;
}

设置目标元素:

div{
    position:absolute;
    width:100px;
    height: 100px;
    margin:auto;
    top:0;
    bottom:0;
    left:0;
    right:0;
}

Tip:这段代码比较优美和灵活。原理其实是:子元素依然相对于父元素定位,但是由于 top:0bottom:0 无法同时满足,且该元素的 margin 又是自适应,因此最终变成了由上下外边距平分尺寸,从而达到垂直居中。至于水平居中,原理也是一样。

  • 方法二:

设置父元素:

.parent{
    position: relative;
}

设置目标元素:

div{
    position:absolute;
    width:100px;
    height: 50px;    
    top: 50%;
    left:50%;
    margin-top: -25px;
    margin-left: -50px;
}

Tip):原理和 2.3 其实一样,只是现在多了一个水平方向的居中。看下图:

或者通过 calc() 一次性设置目标元素的平移距离:

div{
    position:absolute;
    width:100px;
    height: 50px;    
    top: calc(50% - 25px);
    left:calc(50% - 50px);
}

3.2 未知高度和宽度的元素

设置父元素:

.parent{
    position: relative;
}

设置目标元素:

div{
    position:absolute;
    width:100px;
    height: 50px;
    top: 50%;
    left:50%;
    transform: translate(-50%,-50%);
}

Tip:原理和 2.4 一样,不同的是我们现在不知道子元素的宽高,也就不知道要在 top:50%left:50% 的基础上再移动多少距离,但可以确定一定是移动自身宽高的一半,因此把 margin-top:-25pxmargin-left:-50px 对应改为 transform: translate(-50%,-50%)

3.3 任意元素

  • 3.3.1 利用弹性布局一

设置父元素:

.parent{
    display:flex;
    justify-content: center;
    align-items: center;
}
  • 3.3.2 利用弹性布局二

设置父元素:

.parent{
    display: flex;
}

设置子元素:

div{
    margin: auto;
}
  • 3.3.3 利用网格布局一

设置父元素:

.parent{
    display: grid;
}

设置子元素:

div{
    justify-self:center;
    align-self:center;
}
  • 3.3.4 利用网格布局二

设置父元素:

.parent{
    display: grid;
}

设置子元素:

div{
    margin: auto;
}
  • 3.3.5 利用伪元素

设置父元素

.parent {
    font-size: 0;  /* 消除空隙 */
    text-align: center;  /* 实现水平居中*/
    &::before {
        content: "";
        display: inline-block;
        width: 0;
        height: 100%;
        vertical-align: middle;
    }
}

设置子元素

div{
  display: inline-block;
  vertical-align: middle;
}

参考:
https://segmentfault.com/a/1190000003761600
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/92