任何一个Web开发人员都会遇到垂直对齐这个老问题。我在Web领域工作了将近一年,已经被客户问了多次“把这个对齐到窗口中央”或“把那个放到那个的中部”。使用CSS容易实现水平对齐:
对于块级元素(block-level element)
display: block; margin: 0 auto;
对于内联元素(inline element,也叫行内元素)
display: inline-block; text-align: center;
为什么垂直对齐不能这么简单?问题在于网站传统上并不是为了垂直对齐,网页是横向缩放的,高度改变以适应内容。我们幸运的是CSS有多种方法可以绕过这个问题,有些方法好于其他,有些则是十分糟糕,不应该使用。记住这些都是相对的(有时是绝对的),一个可以在某种情况下解决问题的方法可能不能解决另外一种情况的问题。
首先,vertical-align属性
开发人员都有这个时候:首先发现了vertical-align
属性,几分钟后则疑惑它到底有什么含义,特别是在使用这个属性后该死的垂直对齐仍不奏效!!!的确,我们都曾经错误地使用它!
vertical-align
属性规定了排成一行的兄弟元素间彼此是如何对齐的。它适用于内联元素(inline element)和table cell元素。
codepen.io/edenagency/pen/neDlk(译者加)
#parent-container {
background-color: #bc5858;
width: 100%;
text-align: center;
padding: 20px;
}
.child-container {
background-color: #ff933d;
display: inline-block;
padding: 20px;
margin: 0 10px;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
vertical-align: middle;
}
#john {
height: 100px;
}
#dave {
height: 50px;
}
#colin {
height: 20px;
}
#beryl {
height: 120px;
}
#gertie {
height: 35px;
}
(译者加)
适用于内联元素时的值:
baseline
将子元素文本的基线(base line)与父元素的基线对齐。想象基线就是带有横线的写作纸上的横线。这是默认值;
bottom
将子元素的底部与行 的底部对齐;
middle
将子元素的中心线与父元素的中心线对齐(译者注:元素的中心线比基线高一点);
sub
将子元素的基线与父元素的下标基线对齐;
super
将子元素的基线与父元素的上标基线对齐;
text-bottom
将子元素的底部与父元素字体的最底部对齐(译者注:即与父元素的文本内容区的最底部对齐);
text-top
将子元素的顶部与父元素字体的最顶部对齐(译者注:即与父元素的文本内容区的最顶部对齐);
top
将子元素的顶部与行 的顶部对齐;
length
将子元素文本的基线值设为父元素的基线值加上length 所给定的值;
当vertical-align
被误用时,vertical-align: middle
通常是罪魁祸首,最常见的原因是用在了块级元素上。记住,它仅在inline
和inline-block
元素上有效。如果用在了块级元素上,所有子元素都会继承它的值。
vertical-align
也可用于HTML表格的单元格。适用于单元格时的值:
top
将单元格的内容与单元格的顶部对齐;
middle
将单元格的内容与单元格的中心对齐;
bottom
将单元格的内容与单元格的底部对齐;
现在清晰了,让我们来看看怎么解决在块级元素上的问题。
译者注:vertical-align
属性的含义和图解也可参考这里
(译者加)
Line height
这是项简单的技术,你只想中心对齐一行文本时效果很好。也可用于图片,不过这是一种hack,尽量避免使用。
codepen.io/edenagency/pen/GiLdm(译者加)
这个例子包含了两个元素,一个是父元素,一个是子元素。line-height
设置在子元素上,反过来强制父元素调整到与之相同的高度。注意:为让这项技术凑效,line-height
的值必须大于字体大小或图片的高度。为了用在图片上,必须把vertical-align: middle
添加到图片元素。
#parent-container {
background-color: #bc5858;
}
#child-container {
line-height: 300px;
text-align: center;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
}
(译者加)
如我之前所说,这是一种hack,稍后提及能产生同样效果的方法。
优点:
容易实现
缺点:
只能用于一行文本,当用于文本之外时,它不够正规、不够优雅。
CSS表格
是CSS的表格不是HTML的表格。我们可以使用display: table
让一个元素表现得像个表格。这些表格属性基于原来的HTML表格元素,且行为一致。
codepen.io/edenagency/pen/iwBua(译者加)
在这个示例中,父元素当作表格(display: table,译者注),子元素作为表格的单元格(display: table-cell,译者注)。vertical-align: middle
使单元格完美居中,所有的单元格继承了其父元素的高度。
#parent-container {
background-color:#bc5858;
display: table;
width: 90%;
height: 300px;
margin: 0 auto;
padding: 20px;
}
#child-container {
display: table-cell;
vertical-align: middle;
text-align: center;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
}
(译者加)
优点:
完全像HTML表格一样运作,并且语义上正确;
不需要定义高度和宽度。
缺点:
除非定义了宽度,表格会展开到其内容的宽度;
如果你在父元素中需要另一个块级元素并且不想把它当成table cell,事情就变得混乱;
也可以使用HTML表格来实现,然而应该避免使用HTML元素去设计页面的样式,那是CSS的事情,语义上也是错误的,除非你的内容适用于表格,比如列车时刻表。
绝对定位
为了使用position: absolute
来垂直对齐你选择的元素,需要使用像素或百分比定义一个高度。
codepen.io/edenagency/pen/GuqjD(译者加)
有两种方法可居中子元素。第一种选择,如上图所示,用top: 50%
下移子元素,用transform: translateY(-50%)
上移子元素高度的一半,以致子元素的中心与父元素的位于同一行。也可以使用负值的外边距(margin)实现;第二种选择是把子元素的top
, bottom
, left
, right
属性的值均设为0
,外边距均设成auto
,然而用这种方法我得到过不同的结果,最好还是选择第一种。
#parent-container {
background-color: #bc5858;
height: 300px;
width: 500px;
position: relative;
margin: 0 auto;
}
#child-container {
position: absolute;
margin: 0 auto;
top: 50%;
transform: translateY(-50%);
left: 0;
right: 0;
height: auto;
width: 300px;
text-align: center;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
}
(译者加)
优点:
尺寸使用百分比能使元素自适应。
缺点:
需要定义一个高度,有时这是不可能的;
如果不止一个子元素,可能有重叠问题,除非它们也是绝对定位。
你必须记得相对地或绝对地定位你的父元素,否则子元素不会居中。
幽灵元素
这项技术最初在CSS Tricks的博客文章“Centering in the Unknown”中提及。一个幽灵元素(Ghost Element)用于在父元素中居中子元素。因为幽灵元素被赋于了一个100%
的高度,没有必要为父元素或子元素定义高度。当无法知道尺寸时,这是一个理想的方法。
codepen.io/edenagency/pen/trKAu(译者加)
如同Chris Coyier在他的博客中提及的,Michal Czernow建议使用一个伪元素作为幽灵元素,不用另加一个div
且语义上是正确的。
#parent-container {
text-align: center;
background-color:#bc5858;
width: 90%;
height: 500px;
margin: 0 auto;
padding: 20px;
}
#parent-container:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
#child-container {
display: inline-block;
vertical-align: middle;
width: 75%;
text-align: center;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
}
(译者加)
优点:
语义正确。
缺点:
完全像CSS表格一样运作,两项技术都不比另一个更好。
Flexbox
在CSS家族中Flexbox(CSS3 弹性盒模型)是项相对较新的技术。我不想深入太多细节,有很多细节,所以这里是一个对它是做什么的快速描述。
根据www.w3.org:
“在flex布局模型中,flex容器的子元素可以在任一方向展开,并且它们的大小具有相当的弹性,即能增长以填充未使用的空间,也可以缩小以防止溢出父元素。子元素在水平和垂直两个方向的对齐均容易操控。盒子的嵌套(水平的在垂直的中,或者垂直的在水平的中)可以在两个维度上构建布局。”
总的来说,Flexbox仅适用于小型的可伸缩布局。它很容易均等地(或不均匀地)把子元素分成多行或多列,改变元素流动的方向等等。在一个容器中垂直对齐一个单一元素十分地简单。
codepen.io/edenagency/pen/DKCwz(译者加)
当一个父元素从块级元素转变成一个flex元素,它的子元素也自动转变成flex子元素。设置子元素的margin
属性为auto
将把子元素推向其父元素的中心,添加更多的子元素不会影响它的垂直居中,虽然它会相对于它的兄弟元素重新排列。例如,如果有太多的子元素需要固定在同一行上,并且父元素有flex-wrap: wrap
属性,多余的子元素会掉到下一行,所有的子元素均在它们的父元素中居中就像它们是一个整体。
#parent-container {
display: flex;
height: 400px;
width: 100%;
background-color:#bc5858;
margin: 0 auto;
}
#child-container {
width: 90%;
margin: auto;
text-align: center;
font-family: helvetica, arial, sans-serif;
font-weight: 100;
color: #fff;
}
(译者加)
优点:
Flexbox就是用来解决布局问题,因而对于垂直对齐它是理想的。
缺点:
通过使用前缀,它虽然和所有最新的浏览器兼容,但不支持旧版本的浏览器,如:IE9。
如果你想了解关于Flexbox的更多信息,看下CSS Tricks的“A Complete Guide to Flexbox”。
总结 。。。
有这么多的选择,真是奇怪为什么我们发现垂直对齐还是这么难!不幸的是没有一个最佳解决方案。Flexbox看上去更有前景,唯一的缺点是它与旧版浏览器的兼容性,然而我想一旦规范敲定它会是我们要转向的技术。
原文:A Professional Guide: How to Vertically Align Elements Using CSS