面试题:实现一个盒子垂直水平居中?

1,643 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

A journey of a thousand miles begins with single step

招式

定宽高

1. flex 布局

flex 是我在工作中使用最多的布局方式,特别是在移动端,通过对外层 div 设置 flex布局,并且设置justify-content: center; align-items: center; ,可以实现水平垂直居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex 布局</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .innerBox {
      width: 200px;
      height: 200px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

flex 布局.jpg

2. grid 布局

grid 布局实现水平垂直居中,对外部元素设置grid 布局,对内部的元素设置 justify-selfalign-selfcenter

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>grid 布局</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: grid;
    }
    .innerBox {
      height: 200px;
      width: 200px;
      background-color: skyblue;
      justify-self: center;
      align-self: center;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

grid 布局.jpg

3. grid 布局 + margin

grid 布局实现水平垂直居中,对外部元素设置grid 布局,对内部的元素设置 marginauto

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>grid 布局 + margin</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: grid;
    }
    .innerBox {
      height: 200px;
      width: 200px;
      background-color: skyblue;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

grid 布局 + margin.jpg

4. 绝对定位 + 负 margin

绝对定位配合负 margin 实现水平垂直居中,对外部元素设置相对定位 position: relative; ,对内部的元素设置绝对定位 position: absolute; 并且设置距上和左的距离为 50%,再通过设置 margin 距离上和左的边距分别为 -高/2-宽/2 ,实现水平处置居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>水平垂直居中-absolute+margin</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: aliceblue;
      position: relative;
    }
    .innerBox {
      width: 200px;
      height: 200px;
      background-color: skyblue;
      position: absolute;
      top: 50%;
      left: 50%;
      /* margin:-高/2 00 -宽/2*/
      margin: -100px 0 0 -100px;
    }
  </style>
</head>
<body>
  <!-- 已知内部盒子宽高,使用绝对定位和外边距实现 -->
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

绝对定位 + 负margin.jpg

5. 绝对定位 + transform

绝对定位配合 transform 实现水平垂直居中,对外部元素设置相对定位 position: relative; ,对内部的元素设置绝对定位 position: absolute; 并且设置距上和左的距离为 50%,再通过设置 transform 分别向X轴和Y轴的位移 -50% ,实现水平处置居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绝对定位 + transform</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      position: relative;
    }
    .innerBox {
      width: 200px;
      height: 200px;
      background-color: skyblue;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

绝对定位 + transform.jpg

6. 绝对定位 + calc 方法

绝对定位配合 calc 方法实现水平垂直居中,对外部元素设置相对定位 position: relative; ,对内部的元素设置绝对定位 position: absolute; 并且设置距上和左的距离为 50%-高/250%-宽/2,实现水平处置居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绝对定位 + calc方法</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      position: relative;
    }
    .innerBox {
      width: 200px;
      height: 200px;
      background-color: skyblue;
      position: absolute;
      /* - 两边有空格 */
      top: calc(50% - 100px);
      left: calc(50% - 100px);
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

绝对定位 + calc方法.jpg

7. 绝对定位 + left/right/bottom/top + margin

绝对定位配合 left/right/bottom/top 配合 margin 方法实现水平垂直居中,对外部元素设置相对定位 position: relative; ,对内部的元素设置绝对定位 position: absolute; 并且设置距上下左右距离为 0,再通过设置 margin 的值为 auto ,实现水平处置居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绝对定位 + top/right/bottom/left + margin</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      position: relative;
    }
    .innerBox {
      width: 200px;
      height: 200px;
      background-color: skyblue;
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <p class="innerBox"></p>
  </div>
</body>
</html>

效果如下图

绝对定位 + toprightbottomleft + margin.jpg

8. table-cell + inline-block/margin

组合使用 display:table-cellvertical-align、text-align,在内部盒子设置 display:inline-block/margin: auto,使所有行内元素水平垂直居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>table-cell + inline-block/margin</title>
  <style>
  .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: table-cell;
      text-align: center;
      vertical-align: middle;
    }
    .innerBox {
      height: 200px;
      width: 200px;
      background-color: skyblue;
      display: inline-block;
      /* 或者使用 margin: auto;*/
      /* margin: auto; */
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox"></div>
  </div>
</body>
</html>

效果如下图

table-cell + inline-block或margin.jpg

不定宽高

1. flex 布局

当内部盒子由其内部内容自动撑开,宽高不确定时可以使用 flex 布局使其垂直水平居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex 布局</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .innerBox {
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

flex 布局.jpg

2. flex 布局 + marin

当内部盒子由其内部内容自动撑开,宽高不确定时可以给外面的盒子使用 flex 布局,内部使用 margin: auto 使得内部盒子垂直水平居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex 布局 + margin</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: flex;
    }
    .innerBox {
      background-color: skyblue;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

flex 布局 + margin.jpg

3. grid 布局

当内部盒子由其内部内容自动撑开,宽高不确定时可以使用 grid 布局使其垂直水平居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>grid 布局</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: grid;
    }
    .innerBox {
      background-color: skyblue;
      align-self: center;
      justify-self: center;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

grid 布局.jpg

4. grid 布局 + marin

当内部盒子由其内部内容自动撑开,宽高不确定时可以给外面的盒子使用 grid 布局,内部使用 margin: auto 使得内部盒子垂直水平居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>grid 布局 + margin</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: grid;
    }
    .innerBox {
      background-color: skyblue;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

grid 布局 + margin.jpg

5. 绝对定位 + transform

绝对定位配合 transform 同样可以实现内部盒子宽高不确定时的水平垂直居中,原理同顶宽高。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绝对定位 + transform</title>
  <style>
    .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      position: relative;
    }
    .innerBox {
      background-color: skyblue;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

绝对定位 + transform.jpg

6. table-cell + inline-block

组合使用 display:table-cellvertical-align、text-align,在内部盒子设置 display:inline-block,使得宽高不定的行内元素水平垂直居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>table-cell + inline-block</title>
  <style>
  .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
      display: table-cell;
      text-align: center;
      vertical-align: middle;
    }
    .innerBox {
      background-color: skyblue;
      display: inline-block;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

table-cell + inline-block.jpg

7. line-height + text-align

line-height 配合 text-align使用在内部盒子中,使得宽高不定的盒子水平垂直居中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>line-height + text-align</title>
  <style>
  .outsideBox {
      width: 400px;
      height: 400px;
      background-color: antiquewhite;
    }
    .innerBox {
      width: 100%;
      line-height: 400px;
      text-align: center;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="outsideBox">
    <div class="innerBox">这是撑开内部盒子的文字</div>
  </div>
</body>
</html>

效果如下图

line-height + text-align.jpg

心法

内联元素居中

  • 水平居中

    • 行内元素:text-align: center;
    • flex 布局设置父元素: display: flex; justify-content: center
  • 垂直居中

    • 单行文本父元素确认高度:height === line-height
    • 多行文本父元素确认高度:display: table-cell;vertical-align: middle;

块状元素居中

  • 水平居中

    • 定宽:margin: 0 auto;
    • 不定宽:见上文中招式 ---> 不定宽高
  • 垂直居中

    • 定高:position: absolute; top: 50%; left: 50%; margin: -100px 0 0 -100px;
    • 定高:position: fixed; margin: auto;
    • display: table-cell
    • transform: translate(x,y);
    • 不定宽高:grid
    • 不定宽高:flex