不定元素宽高用css实现内容水平和垂直都居中

在开发中常常遇到这个问题,即让某个元素的内容在水平和垂直方向上都居中,内容不只限于文字,多是图片或其余元素。并且咱们但愿不要涉及宽度和高度,也就是说,咱们不知道父元素的宽高,也不知道内容元素的宽高。这篇文章就来总结一下都有哪些方法能够实现水平和垂直都居中。css

不适合的方案

text-align和line-height

显然,使用text-align和line-height的方式更适合单排文字,而不适合本文的需求。特别是line-height,没法保证在不知道高度的状况下还能垂直居中。并且就算是文字,咱们也不知道文字有多少行。html

position:absolute、50%和margin:-px

绝大多数状况下,咱们能够考虑这种方案,让想要居中的元素经过定位和margin为负值进行偏移的方法让它在垂直方向上居中。这种方案不要求父元素的高度,也就是即便父元素的高度变化了,仍然能够保持在父元素的垂直居中位置,水平方向上是同样的操做。可是这里有一个问题,就是咱们的需求每每是内部的这个元素的宽度高度也不肯定,好比是一段文字,你没法保证这段文字的字数多少,因此经过margin为负值来偏移在这种状况下行不通。css3

position:fixed、0和margin:auto

当咱们要制做一个modal dialog弹出框时,好比弹出居中于屏幕的广告或登陆框。这个时候能够考虑一些相对于窗口或网页居中的方案。app

<style>
 .container {
   position:fixed;
   top:0;
   right:0;
   bottom:0;
   left:0;
   margin:auto;
 }
</style>

<div class="container" style="width: 300px; height: 200px; background: #f1f1f1">
 this is a box fixed in center of screen
</div>

这里面最重要的是margin: auto;,对于块级元素而言,肯定了本身的宽度以后,margin:auto能够帮助它居中,即便在position:fixed时。不过必须规定要居中的元素的宽高度,没法知足咱们的需求。函数

position:absolute、0和margin:auto

上面的fixed方案只适合在整个窗口实现居中。fixed会使元素脱离网页,所以在内容流中仍是不适用。在内容流中也想实现居中,能够以下:布局

<style>
    .container {
        position: relative;
    }
    .inner-wrapper {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    }
    .inner {
        position:absolute;
        top:0;
        right:0;
        bottom:0;
        left:0;
        margin:auto;
    }
</style>

<div class="container">
    <p>This is a p</p>
    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

    <div class="inner-wrapper"><div class="inner" style="width: 300px;height: 200px;background: #f1f1f1">
        this is a box fixed in center of screen
    </div></div>
</div>

首先是仿造上面一个方法,使用margin:auto,只不过使用absolute。使用absolute定位的话,父级元素必须也具备position(不为static)。因此把.inner放在一个有position的父级元素.container。这样.inner相对于.container就是居中的(前提仍是.inner要有宽高)。接下来的问题就是怎样让.container具有和内容相同的高宽,经过.container的父级元素为position:relative,.container为absolute,再使用100%使.container和父级元素宽高相同便可。同理由于要设定宽高,因此不知足咱们的需求。flex

正确的方案

display:table和vertical-align:middle

这个方案是理解上最容易的,由于table具有垂直居中的属性,因此很容易经过属性就能实现。this

<style>
.container {
  display: table;
}
.inner {
  display: table-cell;
  vertical-align:middle;
  text-align:center;
}
</style>

<div class="container">
  <div class="inner">
    you own content
  </div>
</div>

这种状况下,咱们能够经过随意改变.inner的宽高,当内部的内容仍然保持居中状态。.net

DEMOcode

position:absolute、50%和translate

在css3里面提供了translate函数,它的主要做用是位移,传给transform属性。

<style>
.container {
  position: relative;
}
.inner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>

<div class="container">
  <div class="inner">
    your own content
  </div>
</div>

html代码和上面同样。translate(-50%, -50%)将会将元素位移本身宽度和高度的-50%。这种方法其实和最上面被否认掉的margin负值用法同样,能够说是margin负值的替代方案。这样你就很是容易理解了。这个方法最厉害的地方是不须要肯定.inner的宽高,而.container的宽高也不须要手动设置,若是它本身自己就被撑大的话。这里只是为了演示方便,才特地给它设置了宽高。

DEMO

vw vh和translate

vh和vw是两个比较偏的单位,是指“viewport的height和width的1%”,好比说50vh就是当前视口(窗口的高度,实验中包含了滚动条)高度的50%。也就是说1vw将等于和1%的window宽度差很少的值。所以用在fixed的时候更加适合。

<style>
 .inner {
   position:fixed;
   top: 50vh;
   left: 50vw;
   transform: translate(-50%, -50%);
 }
</style>

<div class="inner">
    this is a box fixed in center of screen
</div>

其实和使用50%没有太大的差异,由于这时top、left取的50%是相对于父元素的,和margin、padding不同。若是非得要margin的话,就能够从这里衍生出变体:

.inner2 {
   position:fixed;
   top: 0;
   left: 0;
   margin: 50vh 0 0 50vw;
   transform: translate(-50%, -50%);
 }

vh vw只能从窗口的大小去考虑,不适合正常的文本流。不过有的时候能够很是有用,特别是在作全屏应用的时候,好比full page。我把两种方案都放在了演示中,你能够在DEMO查看。

DEMO

:before和display:inline-block

这也是一种处理方式,经过伪类:before在元素内增长新元素后在用display:inline-block,经过高度的处理获得想要的效果。

<style>
.container{
    text-align: center;
}

.container:before {
    content: '';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
.inner {
    display: inline-block;
}
</style>

<div class="container">
    <div class="inner">
        this is a box fixed in center of screen<br>The second line
    </div>
</div>

这个方案是比较特别一些,不是很好理解。首先,.container水平居中没问题。接着,给.container伪类:before设定为height:100%,这样能够用一个伪元素在.container得到与父元素等高的空间。而后用inline-block和vertical-align: middle改变对齐的基线,关于这一点,我也不甚懂,这里有一篇文章能够参考。经过:before以后,.container内的行级元素的对齐基线就跑到居中的位置,也就实现了垂直居中对齐。这个时候,若是里面仅一排文字,其实能够不用.inner,可是上面的例子里面有一个<br>,这就不同了。若是直接把文字放在.container里面,<br>以前的文字会基于:before基线,会保持垂直对齐的状态。可是<br>以后的文字会另起一行,这一行将起始于:before的下一行,因此会在:before的100%高度下面,致使被顶出.container。可是若是把文字放在.inner里面,再让.inner为inline-block,就可使.inner和:before处于同一基线,这样就让整个.inner处于垂直居中的状态。

DEMO

css3 display:flex

css3新增了布局相关的属性,其中flex布局能够很是简单地帮咱们实现咱们想要的效果。

<style>
.container {
    display: flex;
    align-items: center;
    justify-content: center;
}
</style>

<div class="container">
    <div class="inner">
        this is a box fixed in center of screen<br>The second line
    </div>
</div>

简单解释一下,当display: flex时,表示该容器内部的元素将按照flex进行布局。align-items: center表示这些元素将相对于本容器水平居中,justify-content: center也是一样的道理垂直居中。对.container赋予了这些样式以后,做为它的内部元素.inner本身自觉的居中了。并且这里你会发现,因为没有使用text-align: center,.inner里面的文字是不会居中的,也就是说仅仅.inner这个容器居中而已。

DEMO

总结

从上面的几种可行的方案,大体能够分为两类:display对齐方案、translate位移方案。display方案是充分发挥css的布局特性,利用布局和UI引擎的特性来控制布局中的对齐方式。而translate方案则是利用位移,经过先50%的位移,能够是经过position,也能够是经过margin vw vh,可是完成以后,在经过translate把元素拉回去,之因此用translate而不是margin是由于translate是相对于元素自己,而margin不是。


本文发表在个人博客 http://www.tangshuang.net/319...若有疑问或不足之处,请到博客留言

相关文章
相关标签/搜索