水平、垂直居中

接连两次面试被问到水平、垂直居中,答了几种方法,但感觉面试官并不是很满意啊,特意再整理一下各种方法~

该元素宽高已知

1. absolute+负margin

父元素:relative

该元素:absolute, left: 50%, top: 50%, margin-left: 负的该元素宽度的一半,margin-right: 负的该元素高度的一半

<!DOCTYPE HTML>
<html>
<head>
<title></title>
<meta http-equiv="content" content="text/html" charset="utf-8">
</head>
<body>
<style>
    .div1 {
      width: 100%;
      height: 200px;
      background-color: gray;
      position:relative;
    }

    .div2 {
      width:50px;
      height:50px;
      background-color:red;
      position:absolute;
      left:50%;
      top:50%;
      margin-left:-25px;
      margin-top:-25px;
    }
</style>

    <div class="div1">
        <div class="div2">A</div>
    </div>


</body>
</html>

2. 绝对定位居中技术(Absolute Centering)absolute, margin:auto

这种方法的原理参见:绝对定位居中技术(Absolute Centering)

父元素设置为:relative

该元素设置为: absolute, left:0, top: 0, right:0,bottom:0, marign:auto

<!DOCTYPE HTML>
<html>
<head>
<title></title>
<meta http-equiv="content" content="text/html" charset="utf-8">
</head>
<body>
<style>
    .div1 {
      width: 100%;
      height: 200px;
      background-color: gray;
      position:relative;
    }

    .div2 {
      width:50px;
      height:50px;
      background-color:red;
      margin:auto;
      position:absolute;
      left:0;
      top:0;
      right:0;
      bottom:0;
    }
</style>

    <div class="div1">
        <div class="div2">A</div>
    </div>


</body>
</html>

3. flex布局

父元素:display:flex, justify-content: center, align-items: center

<!DOCTYPE HTML>
<html>
<head>
<title></title>
<meta http-equiv="content" content="text/html" charset="utf-8">
</head>
<body>
<style>
    .div1 {
      display:flex;
      width: 100%;
      height: 200px;
      background-color: gray;
      /* flex-direction:row; */
      justify-content:center;
      align-items:center;
    }

    .div2 {
      /* flex: 0 1 auto; */
      width:50px;
      height:50px;
      background-color:red;

    }
</style>

    <div class="div1">
        <div class="div2">A</div>
    </div>


</body>
</html>

该元素宽高未知

1. absolute, transform

父元素相对定位

子元素绝对定位,把定宽的负margin换成transform

<!DOCTYPE HTML>
<html>
<head>
<title></title>
<meta http-equiv="content" content="text/html" charset="utf-8">
</head>
<body>
<style>
    .div1 {
      position:relative;
      width: 100%;
      height: 200px;
      background-color: gray;
    }

    .div2 {
      position: absolute;
      background-color:red;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%)
    }
</style>

    <div class="div1">
        <div class="div2">Abfkadf;</div>
    </div>


</body>
</html>

2.flex布局

<!DOCTYPE HTML>
<html>
<head>
<title></title>
<meta http-equiv="content" content="text/html" charset="utf-8">
</head>
<body>
<style>
    .div1 {
      display: flex;
      width: 100%;
      height: 200px;
      background-color: gray;
      justify-content: center;
      align-items: center;
    }

    .div2 {
      /* position: absolute; */
      background-color:red;
    }
</style>

    <div class="div1">
        <div class="div2">hhhhhh;</div>
    </div>


</body>
</html>

其他

table-cell

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Demo001_displayTable</title>
    <style>
    /*** table-cell middle center组合使用 ***/

    .cell {
        display: table-cell;
        vertical-align: middle;
        text-align: center;
        width: 240px;
        height: 180px;
        border: 1px solid #666;
    }
    </style>
</head>

<body>
    <div class="cell">
        <p>我爱你</p>
    </div>
    <div class="cell">
        <p>我爱你</p>
        <p>亲爱的中国</p>
    </div>
    <div class="cell">
        <p>我爱你</p>
        <p>亲爱的中国</p>
        <div style="width:100px;height:50px;border:1px solid #ccc;display:inline-block">div(inline-block)</div>
    </div>
</body>

</html>

inline-block 1

  • 首先要了解垂直方向的对齐排版需使用 vertical-align,并且只应用于inline level, inline-block level 及 table-cells 元素上;
  • 其次 vertical-align 的对齐就基于每个 line box(行框) 的,简单的说,inline level元素按照 Normal flow 水平排版出一行就会形成一个line box,其高度由内容形成,如果换行,则又是另一个line box,所有一段文本可能会分布在多个line box里,这些不重叠的line box被称作为a vertical stack of line boxes(一个垂直堆叠的线框集合)这些。
  • 换句话说,我们的垂直居中是要在每个line box中进行处理。而上例中我们想让一行文本在名叫demo的高100px的容器里垂直居中,这时有个问题就是demo容器并非该行文本的line box,所以就算定义vertical-laign为middle也无法让该行文本在demo容器中垂直居中。我们知道line box的高度是由内容形成的,这时我们可以额外创建一个与该行文本处于同一line box的元素,同时将新增元素的高度定义为与demo容器相同,此时line box的高度将与demo一致,文本将会在line box内垂直居中,即同样实现了在demo容器中垂直居中。本例我们使用伪对象::after来创建那个新增元素,可以设置新增元素为不可见。
  • 当然,该方案也是有局限性的,因为IE8以下的浏览器不支持伪对象::after

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Demo001_displayTable</title>
    <style>
    #demo {
    height: 100px;
    text-align: center;
    }
    #demo:after {
    display: inline-block;
    width: 0;
    height: 100%;
    vertical-align: middle;
    content: '';
    }
    #demo p {
    display: inline-block;
    vertical-align: middle;
    }
    </style>
    </head>

    <body>
    <div id="demo">
    <p>水平垂直居中的随意内容</p>
    </div>
    </body>

    </html>

inline-block 2

  • 其实如果理解了line box概念,写上述2个例子时,就肯定知道会存在这个杯具。如上,CSS不变,只将文本变长。之前得以实现垂直居中,主要是将文本所在line box撑高了,而如果新增的元素被过长文本挤换行,则它们将不再处于同一line box,那么垂直居中将失效。你可能存疑,不是已将新增元素width设置为0了吗?怎么还能被挤换行。这时你应该知道一个常识,inline level或inline-block level的元素之间的间隙问题,对此问题不做详述。

以下是终极版,包含浏览器兼容,过长问题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Demo001_displayTable</title>
    <style>
    #demo {
        height: 100px;
        text-align: center;
        font-size: 0;
    }

    #demo:after,
    #demo span {
        display: inline-block;
        *display: inline;
        *zoom: 1;
        width: 0;
        height: 100%;
        vertical-align: middle;
    }

    #demo:after {
        content: '';
    }

    #demo p {
        display: inline-block;
        *display: inline;
        *zoom: 1;
        vertical-align: middle;
        font-size: 16px;
    }
    </style>
</head>

<body>
    <div id="demo">
        <p>这是一个终极实现的水平垂直居中实例</p>
        <!--[if lt IE 8]><span></span><![endif]-->
    </div>
</body>

</html>

参考:http://demo.doyoe.com/css/alignment/