参考文章:
Vertical-Align: All You Need To Know
张鑫旭:我对CSS vertical-align的一些理解与认识
张鑫旭:CSS深入理解vertical-align和line-height的基友关系
张鑫旭:CSS vertical-align的深入理解(二)之text-top篇
一 概览
本文从微观层面讲述vertical-align
的工作原理,工作环境。并整理了用vertical-align
实现文本和图片居中的方法。
二 涉及内容概念
1. 顶线,中线,基线,底线
分别对应英文作业本的四条线:
基线最为重要,行内元素就躺在这条线上。且行内元素默认基线和父元素(行框)基线对齐。
中线的定义为:中线位于基线的上方,与基线的距离为小写字母x高度的一半(即0.5ex),而ex同font-size相关,大部分浏览器认为1ex = 0.5em(em同样也是相对单位,不是绝对单位),因此会将基线以上1/4em处作为中线来对齐。
2. 内容区
顶线和底线包裹的区域。
内容区由字体大小和字数决定,跟行高半毛钱关系没有。
给一个没有设置行高的行内元素设置背景,可以看到其内容区:
3. 行高
简单讲就是行内元素所占的高度。
学术点就是内容区加上以内容区为中心上下对称扩展的空白区域,也就是上下行基线之间的距离。
4. 行距(行间距)
上一行的底线和下一行的顶线之间的距离。
也就是:(上一行行高-内容区高度)/2+(下一行行高-内容区高度)/2
5. 行内框(inline-box)
用例子来说明:
<p class="two-p">
<span class="two-span span1">我有自己的行内框</span>
<span class="two-span span2">我也有自己的行内框</span>
<span class="two-span span3">我也有自己的行内框</span>
</p>
虽然三段话在同一行内,但是它们各有各的一块“区域” —— 一个长方体,将他们各自包裹起来,这些长方体在行内不一定对齐。
这些长方体就是行内框。
每个行内元素有自己的行内框。
文本行内框高度=行高=内容区+行距
图片行内框=内容区+padding+border+margin (也就是它自己的盒子模型)
.img{
margin: 10px;
padding:10px;
}
6. 行框(line-box)
图3中的行框就是灰色背景的那块区域。
可见,行框的任务就是包裹同一行行中的行内框,方便页面的渲染。
可以想象成一个大的快递箱,这个快递箱把很多大小不一的小快递箱包裹起来。那么这些大快递箱可以很整齐地摆放,而不是一对小快递箱随意堆在一起。
行框的高度由行内框最高点和最低点决定。
7. 包含框
一个个行框组成了包含框。
三 vertical-align的值
top:元素顶部(行内框)和行框顶部对齐
bottom:元素底部和行框底部对齐
baseline:默认值,元素基线和行框(父元素)基线对齐
sub:下标
super:上标
text-top:元素行内框顶部和行框(父元素)文本(不是图片或其他)的顶部对齐,这里的文本应该指的是行框中没有添加任何样式的匿名文本(自己实验得出,如有误请指正)
因为这个属性用的比较少,所以这里就没有整理了,感兴趣的同学可以自己看一下张鑫旭的另一篇文章:CSS vertical-align的深入理解(二)之text-top篇
text-bottom:元素底部和父元素文本的底部对齐,这里文本同上
middle:元素的中垂点和父元素的基线向上半个“x”距离的那根线对齐,垂直居中的中流砥柱
<length>:具体高度,比如10px
<percentage>:百分比,相对基线偏移行高的百分比。比如,行高100px,偏移10%,即相对基线向上偏移10px
四 行框的基线怎么确定
1. 主要知识点:
- 行内元素基线对齐是和父元素也就是行框的基线对齐。
- 行框的基线会为了满足布局,行高最小化等需求而改变位置。
- 可以通过匿名行内元素“x”来确定父元素基线位置。
2. 详细内容:
正如每个行内元素自己的基线,行框也有自己的基线。
行框的基线由所有行内元素的基线来确定。
行框的基线位置不是固定不变的,是会改变的。
行框需要其基线来满足一些需求,比如,垂直对齐,使行高最小化等等。当它遇到这些需求的时候,就会调整基线的位置。
举个例子,现在有三个行内元素:
<div class="one">
<span class="icon taller"></span>
<span class="icon shorter"></span>
xxx
</div>
行框的基线相对于匿名行内元素“x”的最低点是不对的,它永远和“x”元素的最底点对齐。
现在,给长条的绿色长方形加上一个样式:vertical-align:middle
:
讲道理,我们设置了长条形的样式,应该是长条形下移而不是另外两个行内元素上升呀。
如果从微观来看,长条形撑起了行框的高度。行框内已经没有任何空间给它移动了。可以理解为行高总是尽可能的小。
上面也说过,行框的基线会为了满足一些需求而移动。
所以行框就把基线往上移,移到长条形的中垂线再向上1/2个“x”的距离。(1/2“x”的距离下面会讲到)这样子行高就不会增大。
如果长条形不变,短条形设置vertical-align:middle
:
移动的就是短条形而不是其他两个行内元素了。因为这样做行高的增加是最小的。
所以为什么有时候想要让某一个元素行内居中,改变的是其他行内元素的位置呢?有答案了。
五 莫名的空隙
1. inline-block元素底部的空隙
比如,在一个div中放入一张图片,会发现图片的底部和div的底部不是贴合的,有一个空隙:
同样地,写网页导航的时候,设置每个li
的样式为display:inline-block
,这时候会发现,导航的下面也有一条空隙:
这条空隙其实是行内元素基线和底线之间的空隙。
想要去掉这条空隙,要么把基线移走,要么直接让它消失。
比如,元素设置样式:display:block
:变成非行内元素,基线就不复存在了:
又比如,元素设置样式:vertical-align:middle/text-top/text-bottom/bottom
,将父元素的基线往上移:
再比如,在元素内写入文本,让父元素的基线上移:
六 用vertical-align实现垂直居中
1. 图片(inline-block元素)居中
只需把父元素的行高设置为想要的高度,再给图片添加样式vertical-align:middle
即可。
<div class="container" style="line-height:200px;">
<img src="../static/images/img1.jpg" style="vertical-align:middle;">
</div>
需要注意的是这里的“居中”并不是严格意义上的居中,这里的“居中”是:图片的中垂线和父元素基线向上1/2个“x”字母的高度对齐。
2. 单行文本居中
<div style="line-height:200px;">
<p >xxx</p>
</div>
3. 多行文本居中
把多行文本当成图片处理(对内可以设置宽高,对外是内联元素)
<div class="three">
<p class="three-p">
<span class="three-one">third</span><br>
<span class="three-two">third</span><br>
<span class="three-two">third</span>
</p>
</div>
<style>
.three{
line-height: 200px;
}
.three-p{
display: inline-block;
line-height:1.4em;
vertical-align: middle;
}
</style>
七 直通地心的大坑:vertical-align:middle 失效
有一次进行测试的时候,发现vertical-align:middle
失效了!代码如下:
<html>
<head>
</head>
<body>
<div class="container" style="line-height:200px;">
<img src="../static/images/img1.jpg" style="vertical-align:middle;">
</div>
</body>
</html>
什么?!!!代码完全没有问题啊?!!!!以前都是这样写的!!!!为什么不行了!!!
一个上午都在debug,就是找不到问题在哪里!
后来一哥们觉得,既然代码都是一样的,那就是标准的问题了。
于是,在文档前面加了一句<!DOCTYPE html>
。
居中了!!!!!
原来跟混杂模式还是标准模式有关!
所以使用这个属性一定要使用标准模式!
如果想要兼容旧浏览器,请加上一个空格来撑开行高:
<div class="container" style="line-height:200px;">
<img src="../static/images/img1.jpg" style="vertical-align:middle;">
</div>