vertical-align
一、认识
vertical-align
用来指定行内元素(inline
)或表格单元格(table-cell
)元素的垂直对齐方式。vertical-align
属性可被用于两种环境:
-
使行内元素盒模型与其行内元素容器垂直对齐。例如,用于垂直对齐一行文本内的图片
<img>
-
垂直对齐表格单元内容
注意: vertical-align
只对行内元素、行内块元素和表格单元格元素生效:不能用它垂直对齐块级元素。
二、语法
/* Keyword values */
vertical-align: baseline;
vertical-align: sub;
vertical-align: super;
vertical-align: text-top;
vertical-align: text-bottom;
vertical-align: middle;
vertical-align: top;
vertical-align: bottom;
/* <length> values */
vertical-align: 10em;
vertical-align: 4px;
/* <percentage> values */
vertical-align: 20%;
/* Global values */
vertical-align: inherit;
vertical-align: initial;
vertical-align: unset;
三、取值
3.1 相对行的值
下列值使元素相对整行垂直对齐:
-
top
: 使元素及其后代元素的顶部与整行的顶部对齐。 -
bottom
: 使元素及其后代元素的底部与整行的底部对齐
没有基线的元素,使用外边距的下边缘替代。
3.2 表格单元格的值
-
baseline
: 使单元格的基线,与该行中所有以基线对齐的其它单元格的基线对齐。 -
top
: 使单元格内边距的上边缘与该行顶部对齐。 -
middle
: 使单元格内边距盒模型在该行内居中对齐。 -
bottom
: 使单元格内边距的下边缘与该行底部对齐。
可以是负数。
3.3 相对父元素的值
-
baseline
: 使元素的基线与父元素的基线对齐。HTML
规范没有详细说明部分可替换元素的基线,如<textarea>
,这意味着这些元素使用此值的表现因浏览器而异。 -
sub
: 使元素的基线与父元素的下标基线对齐。 -
super
: 使元素的基线与父元素的上标基线对齐。 -
text-top
: 使元素的顶部与父元素的字体顶部对齐。 -
text-bottom
: 使元素的底部与父元素的字体底部对齐。 -
middle
: 使元素的中部与父元素的基线加上父元素x-height
(译注:x
高度)的一半对齐。 -
<length>
: 使元素的基线对齐到父元素的基线之上的给定长度。可以是负数。 -
<percentage>
: 使元素的基线对齐到父元素的基线之上的给定百分比,该百分比是line-height
属性的百分比。可以是负数。
四、原理
4.1 什么是 baseline ?
字母x
与baseline
的关系: 字母x
的下边缘(线)就是基线baseline
。下图是英文字母在四线格中,每条线的含义(常用的英文本就是四线格的)。
4.2 如何确定 父元素(块级盒子)的 baseline 位置
由于行盒子的baseline
是不可见的,无法直观的确定,如果所有子元素都设置对齐方式了,可以通过在父元素内容最后添加一个字符x
来确定父元素的baseline
。如果想直观的看下行盒子baseline
的位置,可以通过在行盒子css
类上添加一个after
伪元素选择器,内容为x
字符,那么行盒子的baseline
就是x
字母的下边缘线。但是行盒子的baseline
位置会受里面子元素影响而移动(相应字母x的位置也就变动了)
.line-box::after {
content: 'x';
}
4.3 如何确定 inline-level elements(内联级元素)盒子的 baseline 位置
display
属性计算值为:
-
inline
: 内联元素的baseline
, 是里面文本(即使没有字母x
,可以想象文本中有一个字母x
)字母x
的下边缘线 -
inline-block
: 内联块元素baseline
位置的确定规则又分为以下三种(baseline
位置参照下图):-
inline-block
元素盒子里,没有内容(流内内容),是一个空的盒子时:baseline
位置就是该盒子margin-bottom
的边界(没有margin-bottom
值,就是盒子的边界值) -
inline-block
元素盒子里,有内容元素: 并且overflow
属性值为visible
时(默认值),那么该盒子的baseline
位置就是里面最后一个内容元素的baseline
-
inline-block
元素盒子里,有内容元素: 并且overflow
属性值为非visible
时 (比如overflow:hidden
),那么该盒子的baseline
位置就是该盒子margin-bottom
的边界
Preview -
4.4 elements(内联级元素)盒子取不同的值,与块级盒子(父元素)baseline的对齐关系
-
默认情况,不设置任何值:
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...备注:
- 横线: 测试用,用来比对两个子元素和父元素对齐的位置
- x : 先给行盒子内容最后添加一个字母 x 来直观的确定下行盒子的 baseline 位置现象: 两个子元素(红色边框的盒子)内容都为空。因此两个子元素(红色边框的盒子)的基线(
baseline
)都为盒子的底部边界(若有margin-bottom
,则为margin-bottom
)结论: 两个子元素的
baseline
和行盒子的baseline
对齐,其实字母x
所占据的空间,在baseline
的下方还会有一部分。字母x
的整个空间大小如图上绿色区域所示。所以就会有那么一条空白缝隙存在。即使父块级元素里没有字母x
,只有两个子元素盒子,还会存在该缝隙。所以父块级元素里面,内容最后总是存在一个没有没有任何对齐方式的内联元素。这个也就是所谓的幽灵空白节点部分扩展: 那么基于
verticalAlign
方式如何去除幽灵空白节点部门呢? 现在是子元素的baseline
基于父块级盒子的baseline
对齐,导致行盒子里的字母x
临近行盒子底部,字母x
baseline
以下部分所占据的空间撑起这条缝隙。所以我们可以让子元素以别的位置(vertical-align
: 除了baseline
以外其他任何值)对齐父块级盒子的baseline
,这样字母x
就不会临近行父块级盒子底部,也就不会有所谓的缝隙了。 -
vertical-align: middle
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "middle" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "50px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 通过
vertical-align: middle
, 让子元素盒子垂直中点与父块级盒子的baseline
+字母x
高度的一半对齐 -
vertical-align: text-top
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "text-top" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "0px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 子元素盒子的顶部和父块级盒子里内容区域的顶部对齐
-
vertical-align: text-bottom
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "text-bottom" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 子元素盒子的底部和父块级盒子里内容区域的底部对齐
-
vertical-align: sub
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "sub" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 降低子元素盒子的基线到父元素盒子下标的位置
-
vertical-align: super
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "sub" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 升高子元素盒子的基线到父元素盒子上标的位置
-
vertical-align: <percentage>
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", lineHeight:"100px", border: "1px solid red", verticalAlign: "2%" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 百分比的值是相对该元素的
line-height
数值的(元素有默认行高的),具体的升高/降低数值由由该元素的line-height
的值乘以百分比计算得出。相对自己baseline
,升高或较低该元素一定距离。0%
位置就是默认的baseline
-
vertical-align: length
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "4px" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 该值为一定的像素数值,与
vertical-align:percentage
效果类似,除了移动的距离是被计算出来的。 -
vertical-align: top
:实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "top" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 子元素盒子的顶部相对行盒子的顶部对齐
-
vertical-align: bottom
实时编辑器function Test(props) { const box = { border: "1px solid #000", position: "relative", } const item = { display: "inline-block", width: "100px", height: "100px", border: "1px solid red", verticalAlign: "bottom" } const xStyle = { backgroundColor: "#23a576" } const centerLine = { position: "absolute", top: "100px", height: "1px", width: "300px", background: "blue", } return ( <div style={ box }> <div style={ centerLine }></div> <div style={ item }></div> <div style={ item }></div> <span style={ xStyle }>x</span> </div> ); }
结果Loading...现象: 子元素盒子的底部和行盒子的底部对齐
五、场景
5.1 左侧是一个文字,右侧是一个图标,进行水平垂直居中对齐
-
初始情况,未设置任何值
实时编辑器function Test(props) { const box = { border: "1px solid black" } const label = { } const icon = { display: "inline-block", width: "20px", height: "20px", backgroundColor: "blue" } return ( <div style={ box }> <span style={ label }>颜色xx</span> <span style={ icon }></span> </div> ); }
结果Loading...现象: 可以看见,是文字的
baseline
(字母x
的下边缘)和蓝色盒子的底部边界值(baseline
)对齐 -
设置文字和图标的
vertical-align:middle
实时编辑器function Test(props) { const box = { border: "1px solid black" } const label = { verticalAlign: "middle" } const icon = { display: "inline-block", width: "20px", height: "20px", backgroundColor: "blue", verticalAlign: "middle" } return ( <div style={ box }> <span style={ label }>颜色xx</span> <span style={ icon }></span> </div> ); }
结果Loading...现象: 现在文字和图标已经水平对齐了,理论上是文字和图标的垂直中点已经和行盒子的基线+字母
x
高度的一半对齐问题: 文字(
span
标签)的上方(注意是上方)与行盒子(父元素)之间有条缝隙。其实行盒子最后,会存在一个我们看不见的文本盒(w3c
称作struct
),这里我们通过添加一个伪元素,添加一个字母x
,直观的模拟下,该文本盒也会有默认大小(除非font-size
设为0
)的。所以该缝隙,就是由于文本盒本身空间所占据的。优化: 通过给父元素设置
font-size:0
, 子元素单独设置font-size
来去掉缝隙 -
经过
font-size
优化之后, 设置文字和图标的vertical-align:middle
实时编辑器function Test(props) { const box = { fontSize: "0px", border: "1px solid black" } const label = { fontSize: "14px", verticalAlign: "middle" } const icon = { display: "inline-block", width: "20px", height: "20px", backgroundColor: "blue", verticalAlign: "middle" } return ( <div style={ box }> <span style={ label }>颜色xx</span> <span style={ icon }></span> </div> ); }
结果Loading... -
给父元素高度之后,需要给父元素添加
line-height: 父元素内容区高度
再设置文字和图标的vertical-align: middle
实时编辑器function Test(props) { const box = { width: "200px", height: "200px", fontSize: "0px", lineHeight: "calc(200px - 2px)", border: "1px solid black", position: "relative", } const label = { fontSize: "14px", verticalAlign: "middle" } const icon = { display: "inline-block", width: "20px", height: "20px", backgroundColor: "blue", verticalAlign: "middle" } const line = { position: "absolute", width: "200px", height: "1px", top: "100px", backgroundColor: "red", } return ( <div style={ box }> <span style={ label }>颜色xx</span> <span style={ icon }></span> <div style={ line }></div> </div> ); }
结果Loading...