在GitHub阅读,更有味道哦: vertical-align,今晚来我房间聊聊剧本作者博客:blog
还是来GitHub点个Star吧,啊,各位吴彦祖和高圆圆?
写在前面
CSS最令人困惑的属性是什么?vertival-align
因为它总是达不到我们想要的效果
一个logo加一个标题,一个头像加一个名字,要让它们俩垂直居中
一通乱试之后,是不是只能恼怒的用float
或者margin
、padding
今天,我们就来好好调教一下vertival-align
这个傲娇女神
概念
- line box
由若干行内元素占据的一行,会有一个虚拟的框,该行所有行内元素都在这个框里面,W3C把这个框叫做line box
line box
的高度由里面最高的行内元素撑起
如果里面行内元素的总宽度超过一行,则换行显示
- text box
假如line box
里面有一个英文字母x,这个字母的所有属性均继承自父元素
你把字母x用span包裹起来,设置背景颜色,背景颜色覆盖的高度就是text box
的高度
当然,它是由font-size
和line-height
共同决定的
text box
是有其实的,你看那字母x明晃晃的背景颜色
只不过名字是我杜撰的,跟line box
对应
W3C叫它父元素的文字
,我觉得不是很好理解
- 金线
vertival-align
是垂直对齐属性,那它是跟谁对齐呢?
肯定是跟line box
相关的某条线对齐,我把它叫做金线
我们都知道,小写字母x落在text box
的基线上,小写字母g落在text box
的底线上
字母x的下边缘就是vertival-align: baseline;
所要对齐的金线
金线这个名字也是我取的,因为它是一个准绳
其实说白了vertival-align
默认值对齐的就是text box
的基线,所以它跟父元素的font-size
和line-height
都有关系
本文不讨论它们之间的关系,假设父元素的font-size
和line-height
都是固定的
当然不同的属性值,金线的标的也是不一样的,后面会讲到
金线虽然是一个准绳,它却没什么骨气,有时候会去迁就比较高的行内元素
- inline元素和inline-block元素
vertival-align
只对这两种元素(或者变种)有效
一招鲜
咱们先来一个命中率极高的解决方案
回到最前面的问题:一个logo加一个标题,一个头像加一个名字,要让它们俩垂直居中
<div>
<img src="avatar.png">
<span>biu</span>
</div>
你给span
加vertical-align: middle;
,可是达不到效果
你给img
加vertical-align: middle;
,还是达不到效果
不是说好的垂直居中嘛,无赖呀!
其实,你给它们俩都加上vertical-align: middle;
试试,效果是不是出来了?
我们潜意识肯定认为vertical-align
是相对另一个元素对齐,否则怎么会期望达到我们想要的效果呢?
因为vertical-align
是相对金线对齐,每个元素都要分别设置才能统一实现垂直居中
那你说我写在父元素上可不可以?
想走捷径,可以
你在父元素上写vertical-align: middle;
,然后你还要在每一个行内元素上写vertical-align: inherit;
因为vertical-align
默认是不继承的
惊不惊喜!
当然,如果父元素显式的设置了高度,并且比里面任何行内元素都要高,那一招鲜也蔫了,后面有例子
属性值
<style type="text/css">
body {
margin: 0;
}
.line-box {
padding: 0 80px;
background: #ff0;
}
.x {
background: #6ade91;
}
.rect {
display: inline-block;
width: 100px;
margin: 0 20px;
background: #6ade91;
overflow: hidden;
}
.top {
height: 300px;
vertical-align: top;
}
.bottom {
height: 100px;
vertical-align: bottom;
}
.text-top {
height: 200px;
vertical-align: text-top;
}
.text-bottom {
height: 400px;
vertical-align: text-bottom;
}
.middle {
height: 100px;
vertical-align: middle;
}
.baseline {
height: 200px;
vertical-align: baseline;
}
.visible {
height: 200px;
background: #f00;
vertical-align: baseline;
overflow: visible;
}
</style>
<div class="line-box">
<span class="x">x</span>
<span class="rect top">top</span>
<span class="x">x</span>
<span class="rect bottom">bottom</span>
<span class="x">x</span>
<span class="rect text-top">text-top</span>
<span class="x">x</span>
<span class="rect text-bottom">text-bottom</span>
<span class="x">x</span>
<span class="rect middle">middle</span>
<span class="x">x</span>
<span class="rect baseline">baseline</span>
<span class="x">x</span>
<span class="rect visible">
<span>baseline</span>
<span>visible</span>
</span>
<span class="x">x</span>
</div>
通过这张图,我们来聊一聊不同属性值所对应的金线是什么
- top: 金线所在的位置是
line box
的上边 - bottom: 金线所在的位置是
line box
的下边 - text-top: 金线所在的位置是
text box
的上边,也就是字母x背景颜色的上边 - text-bottom: 金线所在的位置是
text box
的下边,也就是字母x背景颜色的下边 - middle: 金线所在的位置是字母x的中部,也就是叉相交的地方
- baseline: 金线所在的位置是字母x的下边
需要注意的是,最后一个矩形和前一个矩形都是vertical-align: baseline;
,不同的是最后一个矩形overflow
的属性值是visible
而前面所有矩形都是overflow: hidden;
为什么呢?
因为如果行内元素里面有文字,而行内元素的垂直对齐又是默认值时,是以行内元素里面最底部的文字基线和text box
的基线对齐
然而如果设置了overflow: hidden;
,就会触发BFC,文字就不会影响对齐点了
我是为了附上文字,方便比较,所以让前面的矩形都触发了BFC
一个例子
我希望实现图片垂直居中,怎么弄?
直接给图片设置vertical-align: middle;
肯定是不行的
因为图片比较高,金线会去迁就图片
结果就是图片纹丝不动,字母x对齐图片中间
<style type="text/css">
body {
margin: 0;
}
.box {
height: 500px;
padding-left: 300px;
background: #ff0;
}
.box img {
width: 200px;
vertical-align: middle;
}
</style>
<div class="box">
<span>x</span>
<img src="Adjani.png">
</div>
我看到网上有一篇文章是这样做的
加一个span标签,变成inline-block
元素,高度和父元素一样高,宽度1px,如果没有背景颜色,它几乎可以忽略不计
然后给图片和这个span同时设置vertical-align: middle;
哎,发现真的可行
他解释说图片需要一个居中对齐的标杆,所以生造一个span,就可以使图片居中了
效果是达到了,然而解释是错误的
图片对齐span,那span对齐谁呢?
其实图片和span都是对齐金线,因为span的高度和父元素的高度一致,金线为了迁就它,就跑到父元素中间去了。然后图片再去对齐金线,于是图片也居中了
标杆永远是金线,只不过金线的位置是动态计算的,有时候要去迁就比较高的行内元素
<style type="text/css">
body {
margin: 0;
}
.box {
height: 500px;
padding-left: 300px;
background: #ff0;
}
.box img {
width: 200px;
vertical-align: middle;
}
.box .blank {
display: inline-block;
width: 1px;
height: 500px;
background: #f00;
vertical-align: middle;
}
</style>
<div class="box">
<span>x</span>
<img src="Adjani.png">
<span class="blank"></span>
</div>
其实还有一种办法,给父元素设置行高等于高度
这时候text box
的高度和父元素的高度是一样的,金线不需要去迁就任何人,图片只管对齐它就是了
<style type="text/css">
body {
margin: 0;
}
.box {
height: 500px;
line-height: 500px;
padding-left: 300px;
background: #ff0;
}
.box img {
width: 200px;
vertical-align: middle;
}
</style>
<div class="box">
<span>x</span>
<img src="Adjani.png">
</div>
总结
首先,line box
里有一个text box
,同时还有一根金线
不同的垂直对齐属性值,对标的金线是不同的,所以多个元素可能对标多根金线,这是没问题的
金线虽然是准绳,但它的高度是动态计算的,有可能要去迁就很高的行内元素
如果行内元素里面有文字,且属性值为baseline的时候,是以里面文字的基线去对齐金线
但如果触发BFC,则上一条失效
张鑫旭讲到过,middle只是近似垂直居中,有兴趣的可以去了解一下
如果金线跟text box
有关,你可以在line box
里放一个没有任何样式的小写字母x,给它一个背景色(好吧背景色也是样式),方便查看金线大概在哪里
金线,当它是text box
的一部分时,肯定跟父元素的font-size
和line-height
是有关的,这个以后咱么再聊
其实大多数情况,一招鲜都可以解决,就是给所有行内元素设置垂直居中
总之,找到金线,你就找到组织了
写在后面
我和你们一样,每次见到一行有多个行内元素就犯怵
所以下定决心弄清楚vertical-align
的原理,希望对大家有一点微小的启发
以上都是我自己的理解,金线也是我自创的,可能不是很严谨
CSS是一门玄学,够用就好
在GitHub阅读,更有味道哦: vertical-align,今晚来我房间聊聊剧本作者博客:blog