css属性 vertical-align
vertical-align作用
指定元素的垂直对齐方式,只对行内元素有效,就是display
的属性为inline、inline-block、inline-table
,再加一个table-cell (<td></td>)
的元素,
行内元素的几条线和行高
图片来自:https://www.zhangxinxu.com/wordpress/2015/06/about-letter-x-of-css/
上行线
图中的ascent
上行线和盒子最上边的一小块高度是上行线高度ascender height
下行线
图中的descent
下行线和盒子最下边的一小块高度是下行线高度descender height
基线
图中红色的线baseline
,也就是字符X
的最下边
中线
图中的 median
,也就是x的底部,再往上多一个x-height
高度后的那条线。
大意就是:middle
指的是基线往上1/2 "x-height"
高度。可以近似脑补成字母x
交叉点那个位置。
由此可见,vertical-align: middle
并不是绝对的垂直居中对齐,我们平常看到的middle
效果只是一种近似的效果。原因很简单,因为不同的字体,其在行内盒子中的位置是不一样的,比方说’微软雅黑’就是一个字符下沉比较明显的字体,所有字符的位置相比其他字体要偏下一点。要是vertical-align: middle
是相对容器中分线对齐,你会发现图标和文字不在一条线上,而相对于字符x
的中心位置对齐,我们肉眼看上去就好像和文字居中对齐了。
行高 line-height
最多的说法是两行字符基线与基线之间的距离,其实也是中线与中线之间的距离,也是上行线与上行线之间的距离,想怎么说就怎么说,高度都是一样的
所以我这样理解:行高是 上行线高度+上行线到下行线之间的高度 +下行线高度
所以,当一个盒子的height=line-height
时,文字就会垂直居中显示了
当行高小于height
时,文字就偏上显示,(因为行高不够所以偏上显示)
当行高大于height时,文字就偏下显示,(因为行高冒了,所以文字就偏下显示)
vertical-align属性值
操作表格单元格
如果是操作单元格td
,表格单元格的值
top
:使单元格内边距的上边缘与该行顶部对齐。(就是盒子模型的content的上边缘)
middle
:使单元格内边距盒模型在该行内居中对齐。(就是盒子模型的content的中间)
bottom
:使单元格内边距的下边缘与该行底部对齐。(就是盒子模型的content的底部)
行内元素值
tip 没有基线的元素,使用外边距的下边缘替代。
baseline
使元素的基线与父元素的基线对齐。
sub
使元素的基线与父元素的下标基线对齐。
super
使元素的基线与父元素的上标基线对齐。
text-top
使元素的顶部与父元素的字体顶部对齐。
text-bottom
使元素的底部与父元素的字体底部对齐。
middle
使元素的中部与父元素的基线加上父元素x-height
(译注:x高度)的一半对齐。
length
使元素的基线对齐到父元素的基线之上的给定长度。可以是负数。
1、正值:基线向上移动
2、负值:基线向下移动
percentage
使元素的基线对齐到父元素的基线之上的给定百分比,该百分比是line-height
属性的百分比。可以是负数。
1、正值:基线向上移动
2、负值:基线向下移动
例子理解
辨别“行内元素的基线”与“行内元素所在行的基线”
1、行内元素的基线:就是字母x的下边沿,就是上面讲的红色的线 baseline
,元素的基线和下行线之间还留有一定的距离,这些距离是留给那些带尾巴的字母或者是汉字的空间,比如j,y,g
等等
2、元素所在行的基线:就是所在行的基准元素,对齐时所依据的那条线。把基准元素所在行当作父元素,也就是说,所在行的基线由他的一个子元素--基准元素所决定。
如果基准元素采用中线对齐,那么所在行的基线就是基准元素的中线,如果基准元素采用顶线对齐,那么所在行的基线就是基准元素的顶线。
所以,基准元素依据哪条线对齐,父元素的基线就是哪条。
另外,根据有无vertical-align属性,还可以分为下面三种情况
(1)全部都没有添加vertical-align时,默认以基准元素的基线对齐。
(2)基准元素添加vertical-align,同一行的其他inline box 没有添加,这时,就是上面说的情况,如果基准元素采用中线对齐,那么所在行的基线就是基准元素的中线,如果基准元素采用顶线对齐,那么所在行的基线就是基准元素的顶线。
(3)当基准元素没有添加vertical-align,同一行的其他inline box添加了,这时添加vertical-align属性的inline box 以基准元素的默认的线对齐,代入例子就是,如果其他元素对齐方式改为vertical-align: top
,那就对齐基准元素的top线,如果时bottom,就对齐bottom线,以此类推
(4)基准元素和同一行的其他inline box都添加了vertical-align
属性,这其实和第三种情况一样,基准元素因为是最高的那一个,无论怎么对齐,都是一样,位置不变,把整一行撑满了,其他元素就以基准元素的线去对齐,该对中线就对中线,该对上线就对上线,以此类推
基准元素
同一行中最高的那个inline box就是这一行的基准元素。
如果这个inline-box没有文字,则没有基线,默认基线位置为下外边距的边缘处,没有外边距时就是元素的最下边。
如果有文字,基线就是上面提到的红色线baseline
,也即字母x
的最下边。
父元素基线计算方式
默认情况下,行内元素的垂直对齐方式都是以基线对齐
没有文字时,如下图所示
- 黄色和绿色都是inline box,默认以这一行的基线对齐
- 这一行的基线就是黄色的基线(因为它在这一行最高,也即是这一行的基准元素)
- 黄色因为没有文字,默认没有基线,所以以它的下边距的边缘处为基线
- 所以绿色框就以黄色块(也即这一行的基准元素)的基线对齐,绿色块本身默认以基线对齐,由于它也是没有文字的inline box,所以默认基线也是它的下边距的最外边缘处。最终就成了如下的布局样式。
注意,inline-block元素间有空格或是换行会产生间隙,使用
font-size: 0;
可去除
<style>
.father {
width: 300px;
border: 1px solid green;
font-size: 0;
}
.son1 {
display: inline-block;
width: 50px;
height: 100px;
background-color: yellow;
margin-bottom: 10px;
}
.son2 {
display: inline-block;
width: 50px;
height: 20px;
background-color: blue;
}
</style>
<body>
<div class="father">
<div class="son1"></div>
<div class="son2"></div>
</div>
</body>
<style>
.son1 {
display: inline-block;
width: 50px;
height: 100px;
background-color: yellow;
margin-bottom: 10px;
}
</style>
- 有文字时,如下图所示
- 黄色和绿色都是inline box,默认以这一行的基线对齐
- 这一行的基线就是黄色的基线(因为它在这一行最高,也即是这一行的基准元素)
- 黄色有文字,默认基线为上面说到的字母
x
的最下边,所以本行的基线就是Son1
的基线 - 所以绿色框就以黄色块(这一行的基准元素)的基线对齐,默认以基线对齐,因为绿色框也是有文字的,所以默认基线也是文字的基线。最终就成了如下的布局样式。
<style>
.father {
width: 300px;
border: 1px solid green;
color: red;
}
.son1 {
display: inline-block;
width: 80px;
height: 100px;
background-color: yellow;
}
.son2 {
display: inline-block;
width: 80px;
height: 20px;
background-color: blue;
}
</style>
<body>
<div class="father">
<div class="son1">Son1</div>
<div class="son2">Son2</div>
</div>
</body>
3、使用vertical-align
实现son2
垂直居中
先来看一个效果,如下图,只是在son1增加了一个vertical-align: middle;
,但是son2却跑到了中间,这是为什么呢?
我们还按照上面一步步分析一下:
- son1和son2都是inline box,默认以这一行的基线对齐
- 这一行的基准元素是黄色块(因为它最高),黄色块有文字,所以基线就是文字的基线,默认以基线对齐
- 但是主动修改了son1(基准元素)的对齐方式
vertical-align:middle
,所以整行的对齐方式就变为了以son1(基准元素)的中线对齐。 - 所以son2的基线就对齐了son1(所在行的基准元素)的中线,就形成了下面的效果。
实际上,son2并没有完全在中间显示,有点偏上,因为son2的基线就是文字的基线,偏下一点,所以要想实现完全居中的效果,可以在son2上也加一个vertical-align: middle
实战:使用伪元素和vertical-align: middle
实现垂直居中
<style>
* {
margin: 0;
}
.parent {
width: 300px;
height: 300px;
border: 1px solid red;
text-align: center;
}
.child {
background: blue;
width: 100px;
height: 40px;
line-height: 40px;
color: #fff;
display: inline-block;
vertical-align: middle;
}
.parent::before {
content: '';
height: 100%;
display: inline-block;
vertical-align: middle;
}
</style>
<body>
<div class="parent">
<div class="child">child</div>
</div>
</body>
分析居中的原理:
- 在parent增加了一个after伪元素,相当于这个伪元素和child变为了兄弟关系
- 伪元素after设置为inline-block,高度设置为父元素的高度,child也设置为了inline-block
- 这时伪元素after和child就变为了处于同一行的inline box
- 默认以基准元素(也即伪元素after,因为它比较高)的基线对齐
- 因为伪元素设置了
vertical-align: middle
属性,所以整行就以伪元素的中线对齐 - child因为有字,默认基线就是正常行内元素的基线,因为基线偏下,所以也给child增加一个
verticle-align: middle
- 让child的中线和基准元素的中线对齐,最终就实现了垂直居中的效果
参考:
https://www.jianshu.com/p/ce7e4a997a2c
https://www.jianshu.com/p/59f31a1704de
https://juejin.cn/post/6844903621327323143#comment
https://developer.mozilla.org/zh-CN/docs/Web/CSS/vertical-align
https://www.zhangxinxu.com/wordpress/2015/06/about-letter-x-of-css/