[译文]CSS的水平/垂直居中:一篇完整的指南

原文:Centering in CSS: A Complete Guide

在CSS中居中是(开发者)抱怨CSS设计的代表问题之一。有人嘲笑说:这有什么困难的呢?我认为,难度不在于解决问题,而在于有如此多的不同解决方法。这些方法在不同的场景下有不同的用处。这让我们手足无措。

让我用一个决策树来帮助我们选择合适的解决方案。

1 水平居中(Horizontally)

你能在一个block-level父元素内水平居中一个inline(或者inline-*)元素,像下面这样:

.center-children {
  text-align: center;
}

HTML:

 <div class="center-children">
        <span>love js</span>
 </div>

这个方法适用于inline, inline-block, inline-table, inline-flex的元素

1.2 居中的对象是一个block-level元素

你能够居中一个block-level元素,通过给(子元素)margin-left和margin-right属性设置auto值。前提是这个元素有一个设定的宽度,否则它会和父元素等宽,从而不会被居中。代码如下:

.center-me {
  margin: 0 auto;
}

HTML:

<div>
    <div style="width:20%;" class="center-me">love js</div>
 </div>

无论你想居中的block-level元素及其父元素的宽度是多少,这个方法都会起作用

1.3 如果有超过一个的block-level元素

如果你有两个或者更多的block-level元素需要在一行中水平居中,有可能更好的方法的是改变它们的display值。以下示例代码两种方式:1,设置display的值为inline-block像1.1一样居中;2,flex布局,不要忘记设置flex-direction的值

 .inline-block-center {
      text-align: center;
  }

  .inline-block-center div {
      display: inline-block;
      text-align: left;
  }

  .flex-center {
      display: flex;
      justify-content: center;
  }

  main div {
      max-width: 125px;
  }
 <main class="inline-block-center">
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row.
   </div>
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row. I have more content in me than my siblings do.
   </div>
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row.
   </div>
</main>

<main class="flex-center">
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row.
   </div>
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row. I have more content in me than my siblings do.
   </div>
   <div>
       I'm an element that is block-like with my siblings and we're centered in a row.
   </div>
</main>

除非你的意思是:你有多个block-level元素互相堆叠起来,那么auto margin的技巧仍然是合适的。

2 垂直居中

在CSS中垂直居中需要那么一点点技巧。

2.1.1 单行

有时候inline/text元素能够看起来像是垂直居中,只是因为在它们上面和下面有一个padding:

.link {
  padding-top: 30px;
  padding-bottom: 30px;
}

示例代码:

<main>
   <a href="#0">We're</a>
   <a href="#0">Centered</a>
   <a href="#0">Bits of</a>
   <a href="#0">Text</a>
</main>
body {
    background: #f06d06;
    font-size: 80%;
}

main {
    background: white;
    margin: 20px 0;
    padding: 50px;
}

main a {
    background: black;
    color: white;
    padding: 40px 30px;
    text-decoration: none;
}

如果因为某种原因,padding不是你的选择,而且你正在尝试居中某段你知道不会被包装的文本。那么有一个居中文本的技巧:让line-height的值等于height的值:

.center-text-trick {
  height: 100px;
  line-height: 100px;
  white-space: nowrap;
}

示例代码:
HTML

<main>
     <main>
         <div>
             I'm a centered line.
         </div>
     </main>
 </main>

CSS:

body {
    background: #f06d06;
    font-size: 80%;
}

main {
    background: white;
    margin: 20px 0;
    padding: 40px;
}

main div {
    background: black;
    color: white;
    height: 100px;
    line-height: 100px;
    padding: 20px;
    width: 50%;
    white-space: nowrap;
    /*与normal的不同在于不换行*/
}

2.1.2 多行

在顶部和底部设置相等padding也能给多行文本设置居中效果。

flex布局对于垂直居中多行文本仍然是起作用的。

2.2 垂直居中一个block-level元素

2.2.1 是否知道元素的高度

在网页布局中,不知道高度是相当普遍的。这出于很多原因:如果宽度改变了,文本流会改变高度; 文本样式的变化也会改变高度。文本数量的变化也会改变高度;有一个固定比例的元素,比如图像,会在resize的时候改变高度;等等。

但是如果你知道高度,你可以向这样垂直居中

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  height: 100px;
  margin-top: -50px; /* account for padding and border if not using box-sizing: border-box; */
}

示例代码:

<main>

  <div>
     I'm a block-level element with a fixed height, centered vertically within my parent.
  </div>

</main>
body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  height: 300px;
  margin: 20px;
  width: 300px;
  position: relative;
  resize: vertical;
  overflow: auto;
}

main div {
  position: absolute;
  top: 50%;
  left: 20px;
  right: 20px;
  height: 100px;
  margin-top: -70px;
  background: black;
  color: white;
  padding: 20px;
}

2.2.2 不知道高度

在top:50%下拉子元素后,将它向上轻推50%,这也有可能居中子元素。

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

2.2.3 如果能使用flex布局

毫无疑问,使用flexbox是很简单的

.parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

示例代码

<main>

  <div>
     I'm a block-level element with an unknown height, centered vertically within my parent.
  </div>

</main>
body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  height: 300px;
  width: 200px;
  padding: 20px;
  margin: 20px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  resize: vertical;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  padding: 20px;
  resize: vertical;
  overflow: auto;
}

3垂直和水平同时居中

你可以结合上述技巧,从而得到完美居中的元素。主要可以分为3种情况:

3.1 元素是否是固定宽度和高度

在你使用50%/50%的绝对布局后,使用负的外边距等于一半高度和高度可以达到目的,这有很好的浏览器件兼容性。

.parent {
  position: relative;
}

.child {
  width: 300px;
  height: 100px;
  padding: 20px;

  position: absolute;
  top: 50%;
  left: 50%;

  margin: -70px 0 0 -170px;
}

示例代码:

<main>

  <div>
     I'm a block-level element a fixed height and width, centered vertically within my parent.
  </div>

</main>
body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  position: relative;
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 200px;
  height: 100px;
  margin: -70px 0 0 -120px;
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 20px;
}

3.2 不知道宽高

如果你不知道宽高,你可以使用tranforms属性,在水平和垂直两个方向使用一个负的50%translate

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

示例代码

<main>

  <div>
     I'm a block-level element of an unknown height and width, centered vertically within my parent.
  </div>

</main>
body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  position: relative;
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 50%;
  transform: translate(-50%, -50%);
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 20px;
  resize: both;
  overflow: auto;
}

3.3 如果能使用flexbox

为了在两个方向上居中,你需要使用两个居中属性

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

示例代码

<main>

  <div>
     I'm a block-level-ish element of an unknown width and height, centered vertically within my parent.
  </div>

</main>
body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 50%;
  padding: 20px;
  resize: both;
  overflow: auto;
}

3.4 如果能使用grid

(grid布局)这个小技巧对于(垂直水平居中)一个元素很有效

body, html {
  height: 100%;
  display: grid;
}
span { /* thing to center */
  margin: auto;
}

示例代码

<span>
  I'm centered!
</span>
body, html {
  height: 100%;
  display: grid;
}
span {
  margin: auto;
}

4 小结:

我们完全可以用CSS实现花式居中。

没有更多推荐了,返回首页