“阿尔法狗”的下棋功力都已经能轻松完爆人类了,无人驾驶汽车都已经能上路了,无人机都开始送快递了,人类的星宇宙探测器都已经飞出太阳系了,人类自身的基因测序工作也完成了相当的程度了……而在CSS中我们竟然还不能用简单的方法去实现垂直居中!?——吐槽完毕!
多年来垂直居中已经成为了CSS领域的“圣杯”,同时也是一个超级大笑话。它具备很显著的特征:
- 垂直居中的需求,很常见!非常常见!!
- 从理论上来分析,似乎实现起来非常的简单。
- 在实践中,难如登天,尤其是涉及不固定尺寸元素的时候。
为了解决这一绝世难题,前端开发者们殚精竭虑琢磨出来了各种方法,有些不实用有些则很巧妙。不知道死了多少脑细胞才能得到一个似是而非的方案。干嘛搞出这么大动静呢?
这个问题,一直在困扰着我,我相信也在困扰着每一个前端。这是一个很普遍却也很棘手的问题,至今没有一个非常有效的解决方案。每次午夜梦回睡梦中惊起都是一身冷汗。后来也就是释然了,为什么一直没有一个能解决垂直居中的“一揽子”的解决方案——就像水平居中text-align:center;
和margin:auto;
一样简单的方法呢?
这其实源于我们的阅读习惯。我们的阅读习惯是从左到右自上到下的阅读顺序。这样的阅读顺序也就决定了,我们阅读“空间”在X轴方向也就是水平方向是可固定的,而在Y轴方向也就是垂直方向是可无限延伸的。这样就决定了在垂直方向去决定元素是否居中也就丧失了意义。
而CSS最初的设计目的是排版,而现在的前端设计者都是在用CSS进行布局。阅读上的习惯加上使用和设计的偏差,使得垂直居中的问题一直不能很好的去实现。我想这个说明大概能解释一部分问题吧
罗列下常用的元素垂直居中方案,以供参考!
本文中的示例结构代码如下所示,不再做特别的说明!
首先是这个是最容易的——已知容器尺寸且已知目标元素尺寸。容器尺寸已知且需垂直居中元素的尺寸已知,可以使用position
的方法来解决。具体的操作就是:容器设置相对定位position:relative;
目标元素设置据对定位position:absolute;
然后又根据尺寸计算出需要定位的top&left or other
。
/*css*/
.warp{
position:relative;
width:500px;
height:250px;
border:thin solid #eee;
background-color:#efefef;
}
.box{
position:absolute;
left:150px;
top:75px;
width:200px;
height:100px;
background-color:#ccc;
}
我们再向前走一步。如果容器尺寸未知,目标元素尺寸已知的情况下,该怎么办呢?我们可以利用定位和margin
的方案来解决。具体实现思路就是,目标元素通过50%
定位至容器中,然后通过margin
设置负值使目标元素“移动”至垂直中间的位置。
.warp{
position:relative;
width:500px;
height:250px;
border:thin solid #eee;
background-color:#efefef;
}
.box{
position:absolute;
left:50%;
top:50%;
margin-left:-100px;
margin-top:-50px;
width:200px;
height:100px;
background-color:#ccc;
}
以上是“早期”的或者说是“最常见”的垂直居中的方案。这些代码在本质上做到了几件事情,先把目标元素的左上角放到视口(或具有相对定位属性的容器元素)的正中心,然后在利用负外边距把它向上、向左移动(移动距离相当于自身宽高的一半),从而实现把元素放到视口(容器)的正中心,从而实现垂直居中。和实现思路是一致的,难道这样就行了么?
NO!NO!最为一名强迫症患者这样肯定是不行的,略微观察之后就会发现如果我们利用CSS3
中强大的calc()
函数,还能让我们的代码还可以再精简一些。
.box{
position:absolute;
left:calc(50% - 100px);
top:calc(50% - 50px);
width:200px;
height:100px;
background-color:#ccc;
}
代码的实现结果是不变的。很好,我们的方案可以经得起一定的考验了。不过上述两种方法的局限在于至少目标元素的尺寸是固定的,可是在通常的情况下,对于那些需要垂直居中的目标元素,其尺寸往往是由自身的内容来决定的。而且calc()
函数在浏览器支持还是十分有限。如果找到一个平衡点。让目标元素可以基于自身百分比计算的属性为解析基准,这个问题就能迎刃而解。
在CSS中允许设置百分比值的属性大都是基于父级元素的尺寸为基准来进行计算的,关于百分比值属性的知识点归纳可以移步至我的另一篇文章CSS关于属性值是百分比的知识盘点。嘿嘿,有些问题的答案其实就来自我们很常见的地方。
translate()
变形函数在使用百分比值的时候,就是基于元素自身的宽高为基准进行换算和移动的,这正是我们需要的。下面需要改造我们的代码,放弃calc()
函数使用translate()
变形函数,让我们彻底解除对固定尺寸的依赖。
我们的结构需要稍微修改下,如果没有内容,translate()
是不会有效果的。
translate
百分比值基于自身计算的属性
而核心的CSS代码就是:
.box{
position:absolute;
top:50%;
left:50%;
transform :translate(-50%, -50%);
background-color:#ccc;
}
当然了,我们要考虑兼容性。需要加一点点私有前缀:
.box{
position:absolute;
top:50%;
left:50%;
-webkit-transform :translate(-50%, -50%);
-moz-transform :translate(-50%, -50%);
-ms-transform :translate(-50%, -50%);
-o-transform :translate(-50%, -50%);
transform :translate(-50%, -50%);
background-color:#ccc;
}
得到的结果
现在,目标元素已经完美居中了。完全满足我们的需求。同时也让我们不在依赖宽高尺寸的限制。
任何技巧性的东西都不会十全十美,上述方法看似完美其实也存在一些“致命的瑕疵”:
- 据对定位对于布局的影响太强烈,脱离文档流的元素不好控制。
- 目标元素内容过多的时候,超过了容器的部分会被裁掉。
- 有些浏览器的渲染算法会使元素可能会被放置在半个像素上,导致显示效果模糊。
关于上述问题,有一些解决方法让我们绕过或是修复问题。这些很难保证它在未来不会出问题。对于强迫症的我来说万万不能忍受。看来还要继续探索一些方案,来让自己在不同的场景需求中有更多的应对能力。
好吧,为了避免文章过长就简单说一下:display: table-cell;
方法利用表格的特性来使元素垂直居中。display:inline-block
是元素获得文本的特性,然后通过伪元素来占位使元素垂直居中。
最风骚的莫过于使用CSS3中的display:-webkit-box
。这种方法的硬伤是浏览器支持范围相对较窄,自身适应性较差。下面是CSS代码。
display: -webkit-box;
-webkit-box-pack:center;
-webkit-box-align:center;
-webkit-box-orient: vertical;
text-align: center
对比下各种方案,个人觉得还是弹性布局——display: flex;
能适应较多数的情况。在使用Flexbox的时候,margin:auto
不仅在水平方向上将元素居中,垂直方向上也会居中。这种方法我们可以不指定任何宽度(需要的时候,还是可以设置的),相对更灵活一些。
.warp{
display:flex;
min-height:100vh;
margin:0;
background:#eee;
}
.box{
margin:auto;
}
而且Flexbox的另一好处是可以将匿名容器(没有标签包裹的文本节点)垂直居中。假设我们有一个容器,内部只有文本没可以操控的目标元素;
这里面只有文本!
我们可以给这个元素指定一个尺寸,然后借助Flexbox中的align-items:center;
和justify-content:center;
属性来实现内容的文本居中。
h3{
display:flex;
align-items:center;
justify-content:center;
width:20em;
height:10em;
background:#eee;
}
关于Flexbox的相关知识可以移步Flex布局语法
垂直居中的方案大致上就这么,每一个方案都不是尽善尽美。前面写的还可以,后面有点不像样子了。主要是有点累了。没吃饭,很饿!!!来让自己在不同的场景需求中有更多的应对能力才是核心对吧。多掌握了解点解决技巧还是有一定帮助的。
好了到这里吧,报告完毕!