css布局 - 垂直居中布局的一百种实现方式(更新中...)

首先将垂直居中的现象和实现方式两大方向细分类如下:

 

接下来逐条累加不同情况下的垂直居中实现。

目录:

一、父元素高度固定时,单行文本 | 图片的垂直居中

1. line-height行高简单粗暴实现法:line-height:Npx(N = 与元素高度相同的值)

2. vertical-middle上场:

二、父元素高度固定时,多行文本的垂直居中

1. 帮多行文本找一个继父来领养他,让继父弥补父元素给他带来的伤害(行高和水平居中对齐的样式修改)

2. margin负边距简单处理一下底部小“裂痕”

三、父元素高度 不 固定时,单行文本 | 图片的绝对垂直居中

1. 新增兄弟节点实力辅助,目标元素轻松上王者

四、父元素高度 不 固定时,多行文本的绝对垂直居中

1. 新增兄弟节点实力辅助,目标元素轻松上王者

五、目标元素宽高固定时,元素的水平垂直居中(经典弹层布局有宽高)

 1. absolute定位飘起来

 2. 上左50%方位值,先让左上角处于视图中心点

 3. margin负边距,再让身子中心点挪到视图中心点

 4. calc自动计算实现

六、目标元素宽高也不固定时,元素依然水平垂直居中(经典弹层布局无宽高)

 1. absolute定位飘起来

 2. 上左50%方位值,先让左上角处于视图中心点

 3. translate -50%偏移,实现自动化偏移相应数值到中心点

 

【非常】 六加一、宽高可定可不定的全屏垂直居中效果

 

七、图片和多行文本的 两列垂直居中(经典布局难题)

1. 两端对齐交给爹地

2. 兄弟齐心,vertical-align: middle;实现居中布局

八、堪称万能钥匙的公共垂直居中解法。无视父元素高度是否固定!无视文字多少行!

(一)灵魂辅助的vertical-align:middle值

(二)拥有家世渊源的table来救场

(三)带着尚方宝剑的display: table-cell

(四)小机灵鬼儿translate对应方向上的-50%

(五)flex大大一句话 水平垂直全拿下

 

正文

一、最简单的,父元素高度固定的单行文本(或单个图片)垂直居中

 实现方式:

1、line-height行高简单粗暴实现法:line-height:Npx(N = 与元素高度相同的值)

正如N的值那样,这种解决方法就是要盒模型是有高度设置的。举例:

假如设计稿元素高度是300px,行高就设置为300px,这样,就可以实现垂直居中的问题。

.box1{

    text-align: center;

    line-height: 300px;

}

如图: 影视二字就可以垂直居中了。

可行性分析:就像图片中看到的那样,只有两个字,他们排在一行不会换行。所以实际应用中要确保一定是单行文本不会换行。因为一旦换行的话,行高就会应用于文字,由于行高过大的原因,会导致剩下的文字跑出画面了。

如右图: 这种情况也可以使用overflow:hidden;做一下保障措施。不过治标不治本。

 

另外补充一点:

有人看到这个现象可能会想是因为line-height导致的,那我给文字包裹一个框比如span,然后给span文字元素单独设置一个正常的行高不久可以了吗?

真的可以了吗?

看图:

中间文字部分就是span包裹的,并设置如下:

.box1 {
    text-align: center;
    line-height: 300px;
}
.span1 {
    line-height: 21px;
    display: inline-block;
} 

结果怎么样呢?

不仅文字和行数少一点的时候,不能完全的垂直居中。甚至文字再多会有这样的现象:

 

 

可见这种假设不合理。

所以单独设置一个行高就解决垂直居中问题看似大快人心,但是代码很不健壮,只局限于特别个别的情况。经不起考验。

那好,现在我直接使用这个方法实现一个宽高固定的图片垂直居中应该也很赞了吧?!

结果一顿操作这个结果我很不满意:

 

 

这不用比较也知道,我的图片没有上下垂直居中啊!毛线。那个标题还那么深,实例打脸。

但究竟是因为什么呢?我往图片后边写了一个x辅助理解,发现图片底部和x字符的底部绝对是对齐的!!这下明白了吧!图片默认是文本基线对其的。文本垂直居中,就到垂直正中间那里。但是图片底部为了与文字底部对其,所以留给顶部的空间就不多了。没有x的时候会有一个空白的换行节点在捣鬼,这也是为什么单独文字的时候看不出毛病,单独图片使用同样的方法却有问题的原因。

 

啊,这就是听张鑫旭老师讲课的收获!

接下来,要实现单个图片的垂直居中效果我只需要让图片和文字水平一条线垂直对其就可以了。

2. vertical-middle上场:

.box1 {
    text-align: center;
    line-height: 300px;
}
img {
    vertical-align: middle;
}

line-height配合vertical-align,搞定。

但是真的要1像素走查的时候,你又会发现,这种做法还是不能完全完全的垂直居中,底部还是差那么一两像素。这个问题接下来再说。

 

二、父元素高度固定的多行文本垂直居中

这种效果其实和中间只有一个图片一个道理,因为你需要帮多行文本找一个继父来领养他,所以结构上就是这样:

1 <div class="content-box">
2     <div class="content">我是多行文本。多行文本水平垂直居中的原理跟上一页图片的实现是一样的,区别在于要把多行文本所在的容器的display水平转换成和图片一样的,也就是inline-block,以及重置外部继承的text-align和line-height属性值。</div>
3 </div>

 

中间content这个元素就好比一个图片,要实现他的水平垂直居中,那么他就得变成一个inline-block元素,(图片本身就是inline-block所以在上一段才没有强调。)

.content-box {
    line-height: 300px;
    text-align: center;
}
.content {
    width: 500px;
    display: inline-block;
    vertical-align: middle;
}

  

不出乎意料的这里出现了上边两个出现过的问题:

1.因为父元素行高的原因,content内部行高过高导致文字行距过大:

       

 

所以content内部就要单独设置行高以覆盖继承自父元素的值:ling-height:21px;(一般改为比字体大小大个4、5像素即可。)

 

2. 因为父元素要对inline-block的子元素content实行text-align:center;限制,导致content内部的文字都居中了,

所以需要text-align:left;纠正。

哇,我惊喜的发现,现在文字行数增多或减少,好像真的看上去垂直居中了哎!

 

 

等等,高兴的太早,又发现和单个图片垂直居中的相同问题,顶部和底部预留的空间好像不一般多啊!

 

红框是我加的before、after等伪类,以显示的让我们看到上下的剩余空间相差多少。

这一点真的和之前的图片问题很接近:

 

 

我把两个例子的代码挪到一个html页面,惊奇的发现,底部剩余空间都是比顶部少4像素!

于是,一不做二不休,我直接使用margin负值让元素再之前的基础上向上4像素,竟真的实现了绝对的垂直居中。

 

 

总结:要想绝对的垂直居中,有了上边的核心代码设置外,还要加一个margin-top: -4px;就可以啦!

不过具体情况具体分析,换个页面,字体大小不一样,对行高的影响也不一样,自然偏差也不一定是4像素,新的负数值再重新计算即可。

 

总结关键点:

1、父子齐心,line-height断难题。

2、鼎鼎大名,margin负边距。

可行性分析:这种再根据当前页或当前元素字体大小调整margin负边距大小值的做法实属有点不妥。

不过还好最近跟大神学了一招“万能胶”。这里暂且按下不表。请看下文如何不动声色且完美的解决这偏差的几像素。

三、父元素高度不固定,单行文本居中

既然父元素高度不固定,那肯定就没有line-height秀的机会了。

(特别说明,第三条系列中的父元素height值只是为了撑开然后填充背景色看的。高度不确定不代表没有高度,所以这里是高度值随意改变,内部子元素永远垂直居中的独秀专场)。

那我们派谁打头阵呢?只见父元素眯眼一想,span,让你的vertical-align出来表演一下吧!我再给你生个小弟弟你们一起秀!

 

1. 单个图片的绝对垂直居中

 

不卖关子,直接上代码和解释:

<div class="box">
    <img src="https://img1.mukewang.com/user/57a6f85b00013c7202090209-100-100.jpg" alt="">
    <span class="assist"></span>

</div>
.box {
    height: 200px;
    text-align: center;
    background: #f5f5f5;
    border: 1px solid #eee;
}
img {
    /* 第一步,元素inline-block化,因为图片本身是所以省去。 */
    /* display:inline-block; */
    /* 第三步,图片和辅助元素同时垂直居中对齐 */
    vertical-align: middle;
}
span.assist {
    /* 第二步,0宽度100%高度的辅助元素 */
    display: inline-block;
    height: 100%;
    /* 第三步,图片和辅助元素同时垂直居中对齐 */
    vertical-align: middle;
} 

所谓三步走策略,这里偷懒把注释都写进代码里了。越是经典的解决方法越是直接背诵就好了。我就不喋喋不休分散看官的注意力了。

再不懂的去慕课网听张老师的课程。链接(3分27秒左右):https://www.imooc.com/video/10407

 

 2. 单行文本的绝对垂直居中

 

1 <div class="box box2">
2     <span class="txts">
3       大小不固定的文字垂直居中
4       <br>
5       多行文本也可以哦!
6     </span>
7     <i></i>
8   </div>

 

.box2 span.txts {
    /* inline-block化,形成块状整体才适用垂直居中。 */
    display: inline-block;
    vertical-align: middle;
}
.box2 i {
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

  这里css有偷懒,只是针对文本的设置,其他普通公用设置见上边第1条单个图片绝对垂直居中那里。

 

 

四、父元素高度不固定,多行文本居中

 

 还是给文本生个小弟弟陪他玩耍:

 

  1. 主体元素inline-block化

  2. 0宽度100%高度辅助元素

  3. vertical-align:middle

 

见第三条第二点。同理,单行文本换成多行即可。。

 

 

五、目标元素宽高固定的水平垂直居中(经典弹层布局)

 

这个很常见了,就不多说什么了:

直接上代码:

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="author" content="guojufeng@ xing.org1^">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>宽高确定的正经弹层</title>
  <style>
    .mask{
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background: rgba(0,0,0,.5);
    }
    .layer{
      width: 300px;
      height: 300px;
      position: absolute;
      top: 50%;
      left: 50%;
      /* margin: -150px auto auto -150px; */
      margin-top: -150px;
      margin-left: -150px;


      text-align: center;
      background: #fff;
      border-radius: 8px;
    }
    span{
      padding: 100px;
      display: inline-block;
    }
  </style>
</head>
<body>
  <h1>我是body里的内容,哦吼吼!xing.org1^</h1>
  <!-- 蒙层 -->
  <div class="mask">
    <!-- 弹层 - 垂直居中实现 -->
    <div class="layer xingorg1">
      <span>我是宽高固定的弹层元素,我实现了垂直居中。</span>
    </div>
  </div>
</body>
</html>

2019-03-03  15:41:55  补calc写法实现:

div{
  width: 100px;
  height: 100px;
  background: #000;
  position: absolute;
  left: calc(50% - 50px);
  top: calc(50% - 50px);
}

  

 

六、目标元素宽高也不固定的水平垂直居中(经典弹层布局)

 

这次重点说说来救场的transform:translate(负值%);

css3中,translate就是指定元素像对应方向偏移,x是水平偏移,y是垂直方向的偏移,因为这篇是方法汇总,不做过多介绍,请自行查看w3c或实验。也看移驾这篇文章:https://www.cnblogs.com/padding1015/p/9550142.html

 

不过他有一个屌炸天的特性是,当偏移数值的单位为百分比的时候,会相对于本身的长宽来计算偏移值。

比如元素的宽度是300px的时候,我们让他再向左移动50%宽度,配合上left:50%;就能实现居中。

刚好,translateX(-50%)自动计算得到的就是元素自身宽度的50%值。所以,我们不需要知道目标元素的宽高也一样能实现居中了。

对于这一特性,这个慕课网问答这里讲的很好:http://www.imooc.com/qadetail/129282

 

他除了适用于这个弹层的场景,同样适用于其他场景的居中。因为即使不浮动,translate移动对兄弟元素没有影响。

请看:

 

这种现象和margin移动不一样。只不过其他场景使用translate有点大材小用。

 

关键点分析:

利用transform来实现垂直居中布局

box盒使用固定宽度的width+margin auto,实现水平居中。

position:relative,top: 50%;实现垂直方向的偏移。

因为没有高度固定,所以无法确切的使用margin-top负值实现垂直居中

但是translateY属性,会自动根据盒子高度计算偏移值。translateY(-50%)就会向上偏移50%的高度值。所以:

position:relative(或者absolute);  +  top: 50%;  +  transform:translateY(-50%);可以实现垂直方向的绝对居中效果。

 

但是,学习就要举一反三,我们同样可以

利用transform来实现水平居中布局

position: absolute;

left: 50%;

transform: translateX(-50%);

一样可以实现!

 

 那么,如果跟之前的垂直居中合并起来的话,transform是不是也可以写一条呢?

当然,具体写法如下:

transform: translate(-50%,-50%);

 

 

好了,废话说的再多也不如贴源码运行一探究竟:

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

<head>
  <meta charset="UTF-8">
  <meta name="author" content="guojufeng@ xing.org1^">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>translateY实现垂直居中</title>
  <style>
    html,
    body,
    ul {
      height: 100%;
      margin: 0;
    }
    .mask {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background: rgba(0, 0, 0, .5);
    }

    .layer {
      position: absolute;
      top: 50%;
      left: 50%;
      /* transform: translateX(-50%) translateY(-50%); 这种写法也可以,相当于写两个translate*/
      transform: translate(-50%,-50%);
      text-align: center;
      background: #fff;
      border-radius: 8px;
    }
    .box {
      /* width: 500px;*/
      /* height: 350px;  */
      padding: 30px 10px;
      background: rgba(255, 51, 255, 0.2901960784313726);
    }
  </style>
</head>

<body>
  <h1>我是body里的内容,哦吼吼!xing.org1^</h1>
  <h1>translate负值实现元素的水平垂直居中</h1>
  <!-- 蒙层 -->
  <div class="mask">
    <!-- 弹层 - 垂直居中实现 -->
    <div class="layer xingorg1">
      <div class="box">
        <ul>
          <li>关键点</li>
          <li>left: 0;
            right: 0;
            bottom: 0;
            margin: auto;</li>
          <li>top: 50%;</li>
          <li>transform: translateY(-50%);</li>
          <li>这些li是为了撑开box的高度</li>
        </ul>
      </div>
    </div>
  </div>
</body>

</html>

但是,bug来的太突然、、、2018-09-26 10:29:06 

上边的gif太快,是不是没发现这个方法的一个问题呢?

来个静态截图:

 

没看出来?那看下边这个图:

发现了吗?

div.box 我并没有设置宽度,但是他默认展示的最大宽度(在没有border和padding的情况下),是父元素(body)宽度的50%!

后来我就想因为什么?

在张鑫旭大神的absolute课程中,讲过方位值left和right这些,如果设置50%,是从父元素原本宽度的50%处开始左边距的。(当然这不是人家的原话,是我的理解)。

也就是说,在我不设置right的情况下,left:50%;也就相当于这个box盒子剩下的活动空间就是从left: 50% 到 最右边了。

 要说明这个,其实直接去掉transform的居中效果就可以一眼看出来了:

 如果再狠点,right也设置50%,那box的宽度就被挤没了。

 

发现这个问题后,我恍然大悟虽然这个方法很好用,但是他还是有很多局限性。最好只用在垂直居中上,毕竟有很多场景不适用。

比如这种:

我要想要中间那块根据文案的多少,宽度自适应,并且还能永远水平居中的话,就不适用上边这种方案,不然会发生车祸现场:

那么,这种情况的水平居中该怎么做呢?

一眼明了,水平居中简单吧!直接给内联元素的父亲设置text-align就行了。

 

不过最近我又发现了原理差不多的另一种absolute定位元素实现居中的写法,现补充如下:(2019-01-08 14:45:04 )

【非常】 六加一、宽高可定可不定的全屏垂直居中效果

上下左右0+自适应的margin实现

如下:

给一个宽高300的定位元素垂直水平居中。

* 注意这里宽高300虽然有要求,但是经我实际测试,宽高自动增删都不影响垂直水平居中,说明在宽高不定的元素中,也就可以实现。

不说废话了,代码如下:

<div class="clas class3">test3</div>

 css:

 

七、图片和多行文本两列的垂直居中(经典布局难题)

1、兄弟们一起 vertical-align:middle;

先看诱惑人的结果,就是不管文字单行还是多行,不管图片改成多大,都能实现的效果:

 

然后再说解决方法。核心就是用了 vertical-align:middle;  

html结构:

<div class="box">
    <span>单行文字</span>
    <img src="https://img1.mukewang.com/user/57a6f85b00013c7202090209-40-40.jpg" alt="">
  </div>
  <div class="box">
    <span>多行文字<br />文字文字文字文字<br />文字文字文字文字</span>
    <img src="https://img1.mukewang.com/user/57a6f85b00013c7202090209-40-40.jpg" alt="">
  </div>
  <div class="box">
    <span>因为vertical-align只对inline/inline-block元素起作用,而浮动会让元素block水平化,就不能使用vertical-align对齐了</span>
    <img src="https://img1.mukewang.com/user/57a6f85b00013c7202090209-40-40.jpg" alt="">
  </div> 

 

关键点1:外边的box实现两端对齐

因为vertical-align只对inline/inline-block元素起作用,而浮动会让元素block水平化,就不能使用vertical-align对齐了。

所以这里才用  text-align: justify;  附加给父元素,实现图文的两端对齐效果

 

关键点2:文本span元素  

vertical-align: middle;

 

这里文本因为需要有个宽度值限制,所以inline-block化了,要知道,不是必须即可。

关键点3:img元素

vertical-align: middle;

 

 

八、堪称万能钥匙的公共垂直居中解法。无视父元素高度是否固定!无视文字多少行!

 

(一)灵魂辅助的vertical-align:middle值

具体见上边第三条的例子,用一个span空标签放到需要垂直居中元素的后边或者前边,作为辅助兄弟元素。

同时给这个辅助元素和目标元素vertical-align:middle;  display:inline-block;一顿操作即可。

css 中有一个用于竖直居中的属性 vertical-align,在父元素设置此样式时,会对inline-block类型的子元素都有用。

 

(二)拥有家世渊源的table来救场

就像上例中辅助元素的vertical-align原理一样,td 标签默认情况下就默认设置了 vertical-align 为 middle,所以我们不需要显式地设置,使用table布局就可以完成完美的自动水平垂直居中了。

但是这种布局方式毕竟拘束,在实现垂直居中后,还需要一大堆的代码把tabel的样子抹掉。

所以知道有这种方法,平时根本不用也没必要用,我也不去实践了。

 

(三)带着尚方宝剑的display: table-cell

即,设置块级元素的 display 为 table-cell。

之所以说display:table-cell; 是带着尚方宝剑的,是因为这么做就相当于设置为表格单元显示。

但这种方法兼容性比较差,只是提供大家学习参考。

在 chrome、firefox 及 IE8 以上的浏览器下可以设置块级元素的 display 为 table-cell(设置为表格单元显示),激活 vertical-align 属性,

注意 IE6、7 并不支持这个样式, 兼容性比较差。

<div class="container">
    <div>
        <p>看我是否可以居中。</p>
        <p>看我是否可以居中。</p>
        <p>看我是否可以居中。</p>
    </div>
</div>
<style> .container {
    height:300px;
    background:#ccc;
    display:table-cell;
    /*IE8以上及Chrome、Firefox*/
    vertical-align:middle;
    /*IE8以上及Chrome、Firefox*/
}
</style>

  这种方法的好处是不用添加多余的无意义的标签,但缺点也很明显,它的兼容性不是很好,不兼容 IE6、7而且这样修改display的block变成了table-cell,破坏了原有的块状元素的性质。

 

(四)小机灵鬼儿translate对应方向上的-50%

具体原理和使用方法及案例见上边。不再赘述。

 

(五)flex大大一句话 水平垂直全拿下

 

 

这个相信不用我说,大家一看就明白怎么回事了。

Flex弹性盒布局属性,此系列中还有两个属性justify-content align-items 分别用于实现水平居中和垂直居中。

具体flex的学习可以参考这两篇:

Flex 布局教程:语法篇  作者: 阮一峰

http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

 

Flex 布局教程:实例篇作者: 阮一峰

http://www.ruanyifeng.com/blog/2015/07/flex-examples.html

 

简易的代码见下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="author" content="guojufeng@ xing.org1^">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>万能方法</title>
</head>
<body>
  <div class="flex xingorg1">
    <span>前端小学生~ _xing.org1^</span>
  </div>
  <div class="flex xingorg1">
      <span>不会搞艺术的程序员不是好的设计师 _xing.org1^ 不会搞艺术的程序员不是好的设计师 _xing.org1^ </span>
    </div>
  <style>
    .flex{
      margin-bottom: 10px;
      padding: 20px;
      width: 300px;
      height: 300px;
      background: #f5f5f5;
      border: 1px solid #eee;
      /* flex写法 */
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
  </style>
</body>
</html>

虽说古老的ie不支持这种布局,但是写上hack后,用在移动端的项目中简直完美啊。

小程序不就默认这么写的么。

 

 

 

 

 

 

 

2018-09-11 12:42:49

声明:

  请尊重博客园原创精神,转载或使用图片请注明:

  博主:xing.org1^

  出处:http://www.cnblogs.com/padding1015/

 

posted @ 2018-09-11 14:54  xing.org1^  阅读(22829)  评论(10编辑  收藏  举报