对于前端来说,用CSS实现垂直居中是常见的工作,但自从flex出现后,因为做的差不多都是移动端的页面,大家基本上都用flex了。为了方便大家写PC端样式时可以少走弯路,我把之前工作中用到过的和别人总结的垂直居中方式一并总结在这里。

        基本的DOM结构如下:

<!--hexoPostRenderEscape:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;parent&quot;</span>&gt;</span><br><span class="line">    &lt;div id=<span class="string">&quot;child&quot;</span>&gt;&lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

margin-top / padding-top

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    .parent {
    width: 300px;
    height: 300px;
    }
    .child {
    width: 100px;
    height: 100px;
    margin-top: 50px;
    }

    ---- 或者 ----

    .parent {
    width: 300px;
    height: 300px;
    padding-top: 50px;
    box-sizing: border-box;
    }
    .child {
    width: 100px;
    height: 100px;
    }

  • 兼容性

margin兼容性

        本来我是不打算写这种方式的,但笨方法也是一种方法。

flex

  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .parent {
    display: flex;
    height: 300px;
    align-items: center;
    }
    .child {
    width: 100px;
    height: 100px;
    }
  • 兼容性

flex兼容性

        flex在移动端的兼容性都很好,但是如果要在PC端使用的话,IE 10 以下就不要考虑了,IE 10 和11 也有一些兼容性问题需要注意:flex兼容性

绝对定位 + transform

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .parent {
    position: relative;
    height: 300px;
    }
    .child {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
    }

  • 兼容性
    transform兼容性

        transform是CSS 3的属性,自然对IE 8 及以下是不兼容的,IE 9 以上使用前缀就可以了。

绝对定位 + 负margin

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .parent {
    position: relative;
    height: 300px;
    }
    .child {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    margin-top: -50px;
    }
  • 兼容性

负margin兼容性

        这种实现方式的兼容性没什么好质疑的,CSS 2 的属性,兼容到IE 6(虽然我们早就不考虑IE 678 的兼容性了)。这种方式不够灵活的一点是,margin值必须指定为自身高度的一半,这就意味着这种实现方式只适用于child高度明确的情况。负margin在工作中还有许多应用场景,比如在父级宽高一定的情况下扩充子级宽高,利用负margin做叠加,和padding配合实现左右div等高等等。总之,在写样式的时候要记得margin可以为负的哦。

table-cell

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .parent {
    height: 300px;
    display: table-cell;
    vertical-align: middle;
    }
    .child {
    width: 100px;
    height: 100px;
    }
  • 兼容性

table-cell兼容性

        这种实现方式不兼容IE 67,Firefox 2 有一些bug,但鉴于目前Firefox 2的版本占比为0,使用table-cell是不用考虑兼容性的问题的。这个例子只是展示table-cell这个属性在垂直居中中的作用,实际工作中我们常常使用table的一整套DOM。由于浏览器生成table会进行多次重排重绘,非常损耗性能,因此如果不是后台系统或者要展示比较规范的表格类型的数据的时候,尽量选择其他的实现方式。

绝对定位 + margin: auto

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .parent {
    position: relative;
    height: 300px;
    }
    .child {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    }
  • 兼容性

margin:auto兼容性

        上图是margin: auto的兼容性。需要注意的是图中标“1”的浏览器,在怪异模式下是不支持margin:auto的。如果你对怪异模式很陌生,那么记得保证你的html页面开头是这样的声明就行,这段声明可以保证你的页面以标准模式渲染。

grid

        使用grid其实已经超出我们在开头规定的DOM结构的范围了,但是因为grid和flex相比,可以更轻易的实现二维布局,所以还是现在这里认识一下
吧。使用grid实现垂直居中的DOM结构如下:

<!--hexoPostRenderEscape:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;parent&quot;</span>&gt;</span><br><span class="line">    &lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;child1&quot;</span>&gt;&lt;/div&gt;</span><br><span class="line">    &lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;child&quot;</span>&gt;&lt;/div&gt;</span><br><span class="line">    &lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;child2&quot;</span>&gt;&lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

        和之前规定的DOM结构相比,我们在在子级增加了两个辅助的div,通过设置子级三个div的高度来实现中间div的垂直居中。如果不设置grid-template-rows的话,三个子级div会是相同的高度,也是垂直居中的。

<!--hexoPostRenderEscape:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.parent &#123;</span><br><span class="line">    height: 300px;</span><br><span class="line">    display: grid;</span><br><span class="line">    grid-template-rows: 50px 200px 50px;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->
  • 兼容性

margin:auto兼容性

        嗯,grid最大的问题就是兼容性。PC就不要考虑了,M的如果你的项目不需要兼容那些飘红的浏览器,就可以先用起来了。grid详细的兼容性在这里:grid兼容性

line-height + vertical-align

        我们都知道使用line-height实现文本的垂直居中,同样的,我们也可以使用line-height和vertical-align实现图片的垂直居中。

<!--hexoPostRenderEscape:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;div <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;parent&quot;</span>&gt;</span><br><span class="line">    &lt;img <span class="class"><span class="keyword">class</span></span>=<span class="string">&quot;child&quot;</span> src=<span class="string">&quot;demo.jpg&quot;</span>&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;style&gt;</span><br><span class="line">    .parent &#123;</span><br><span class="line">        line-height: 300px;</span><br><span class="line">    &#125;</span><br><span class="line">    .child &#123;</span><br><span class="line">        width: 100px;</span><br><span class="line">        height: 100px;</span><br><span class="line">        vertical-align: middle;</span><br><span class="line">    &#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

        按照line-height可以使inline元素垂直居中的思路,我们也可以利用line-height实现任意div的垂直居中,前提是设置其为 inline-block:

<!--hexoPostRenderEscape:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">.parent &#123;</span><br><span class="line">    height: 300px;</span><br><span class="line">    line-height: 300px;</span><br><span class="line">&#125;</span><br><span class="line">.child &#123;</span><br><span class="line">    display: inline-block;</span><br><span class="line">    width: 100px;</span><br><span class="line">    height: 100px;</span><br><span class="line">    vertical-align: middle;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

        为什么要把line-height放到最后,是因为vertical-align:middle并不是真正的垂直居中(见下图),而且各个浏览器、IOS和安卓的渲染还有些差异,如果你的项目对还原设计稿的要求很高,这个方案就放弃吧。

垂直居中偏差

        (完结)