CSS基础:内联元素
简介
内联元素由于涉及到文本字体,读写方向,汉字和字母差异等诸多方面的影响,因此其盒模型比块级元素更加复杂,对于内联非替换元素,比如一行文本,主要由以下几种框构成:
"em 框",也称为字符框( "character box" ),对 <span> 这种内联非替换元素设置背景,显示出来的区域就是它,顾名思义,由于 1em 的大小等于1倍 "font-size" 的大小,因此 "em框" 的高度从感知上来讲恰好等于 "font-size" 的大小;
"内容区",现在考虑这种情况:在一个 <p> 标签中插入两个或多个 <span> 标签,每个 <span> 标签都有一个自己的 <em> 框(因为可以单独给某个 <span> 标签设置 "font-size"),而这些 "em框" 的组合就称为内容区;
“行内框”,与 "em框" 不同,行内框的高度是由 "line-height" 的大小决定;
"行间距",是 "line-height" 与 "font-size" 之差,这个差实际上要分为两半,分别应用到内容区的顶部和底部,称为半间距;
"行框",行框的上边界位于一行中最高行内框的上边界,行框的下边界位于一行中最低行内框的下边界;
如图所示:
内联非替换元素盒模型的一些特性:
1.垂直方向上的内边距,边框和外边距无效,它的高度仅由行高决定。虽然可以设置这些属性,例如:{ border: solid 2px #000; } 但是高度计算会被忽略;
2.如果一个行框没有足够的水平空间容纳一个或多个行内框,那么会创建一个新的行框,换句话说一个行内元素是可以跨行存在的;
3.当一个行内框跨行时,在逻辑上任然是单一的框,因此,水平方向的内边距,边框和外边距只会作用于这个行内框的第一行开始部分和最后一行结束部分;
字母 x 与 css 世界的基线
凡是涉及到内联元素的大都离不开 "line-height" 和 "vertical-align" 两个属性,而这两个属性的定义均与基线(" baseline ")有关,"line-height" 的定义就是两行基线之间的间距,"vertical-align" 的默认值就是基线对齐,那基线到底指的是什么呢?
首先,对于英语来说,大部分字母坐落在一条看不见的线上,称为基线,由于不同字体基线高度也应该不同,比如 "微软雅黑" 下沉就比较厉害,而 "宋体" 就显得比较方方正正,为了解决字体带来的差异,聪明的 css 规范制定者们将基线定义在字母 "x" 的下边缘,如图:
另外,还有几个衍生而来的概念,比如:"x-height",指的是一个字母 "x" 的高度,单位 "ex" 就是这么来的,css 中有些属性值的定义就与它有关,最典型的代表就是 { vertical-align:middle; },这里的居中对齐就是将元素行内框的垂直中点与行框的基线往上 0.5ex 处的一点对齐,也就是 "x" 的交叉点,例如:
<!-- html --> <div class="bg"> <span class="span1">xxx</span><span class="span2">xxx</span> </div>
//css .bg { background: #000;color: #333; } .span1 { font-size: 40px;background: lightblue;vertical-align: middle; } .span2 { font-size: 70px;background: yellow; }
运行结果:
不好意思,运行结果貌似跟规范里描述的差距也太大了吧,那究竟是什么原因造成的呢?一方面 { vertical-align: middle; } 确实有着谜一样的规则,不然也不会有这么多人在网上问 "vertical-align" 垂直居中为什么无效类似的问题了,另一方面,在许多教程文档和参考手册中将这个值的作用讲得非常简单:用于内联元素垂直居中,稍微详细一点的就像上面那样,将元素行内框的垂直中点与行框的基线往上 0.5ex 处的一点对齐。关键就在这个 "ex" 上,它是一个相对单位,如果没有在父容器上设置字体大小,那么它将继承浏览器默认字体大小,不同浏览器字体大小不同,除此之外,还有各种全局字体样式,最后的结果可想而知。
解决办法就是事先在父容器规定字体的大小,上面例子中,基线位于黄色背景 "xxx" 的下端,它的 "font-size" 为 "70px",于是:
//css .bg { background: #000;color: #333;font-size: 70px; } .span1 { font-size: 40px;background: lightblue;vertical-align: middle; } .span2 { font-size: 70px;background: yellow; }
运行结果:
这次结果就很完美了。
关于 line-height
"line-height" 决定了内联非替换元素的高度,默认值是 "normal",还支持数值,百分比值和长度值:
"normal":默认值在不同的浏览器中不同,而且与 "font-family" 有关;
数值:例如,{ line-height: 1.5; },其最终结果就是和 "font-size" 相乘后的值;
百分比值:例如,{ line-height: 150%; },其最终结果就是和 "font-size" 相乘后的值;
长度值:就是带单位的值,例如 { line-height: 15px; },{ line-height: 1.5em; } 等;
乍一看,{ line-height: 1.5; },{ line-height: 150%; },{ line-height: 1.5em; } 好像都是与 "font-size" 有关的计算值,但是实际上数值与另外两个有一点不同,那就是继承细节有所差别:如果使用数值作为 "line-height" 的属性值,那么它的所有子元素继承的都是这个值,如果使用百分比值或长度值作为 "line-height" 的属性值,那么它的子元素继承的是与 "font-size" 计算后的最终计算值。
关于 vertical-align
vertical-align 几个常用属性值的解释:
"top",将元素行内框的顶端与包含该元素的行框的顶端对齐;
"bottom",将元素行内框的底端与包含该元素的行框的底端对齐;
"text-top",将元素行内框的顶端与内容区的顶端对齐;
"text-bottom",将元素行内框的底端与内容区的底端对齐;
"middle",元素行内框的垂直中点与行框的基线往上 0.5ex 处的一点对齐;
"长度值",相对于基线的偏移量(允许负值);
"百分比值",相对于基线的偏移量(允许负值),基数就是 "line-height" 的高度;
关于内联元素自带的空白节点
浏览器等用户代理会在所有的内联元素的前面或者后面插入一个空白节点,称为支柱 ( "strut" )。在这里有一个前提是文档需要声明 <!DOCTYPE html>,即使用 html5 版本编写。
示例1:
<!-- html --> <div class="box"><img src="test.jpg" alt="" /></div>
//css .box { background: lightblue; }
运行结果:(图片的底部留有空隙)
示例2:
<!-- html --> <div class="box"><span>xxx</span></div>
//css .box { background: lightblue; line-height: 70px; } .box span { font-size: 20px; line-height: 30px; }
运行结果:(大部分人会认为 <span> 标签的 "line-height" 会覆盖继承来的样式,所以容器的高度应该是30px,对不对?实际上,由于这个空白节点的存在,它也是内联元素,也能响应 "line-height" 形成高度,所以容器最终的高度为70px)
以上两个例子用于证明空白节点确实存在,它其实是 "line-height" 和 "vertical-align" 共同作用的结果,只要消除其中任一个,就能消除空白节点的影响,比如:
将图片设置为 { display:block; },由于空白节点只会和内联元素同时出现,因此将图片设为块级元素可避免之;
将 "line-height" 的值设置得足够小,因为内联元素的高度都是由 "line-height" 撑开的;
将 "vertical-align" 的值设为除 "baseline" 以外的值,例如 "top","middle" 等;
使用 "font-size" 间接控制 "line-height" 的大小,例如在父容器设置 { font-size: 0; },"line-height" 也跟着变成0了;
示例3:(利用空白节点将元素垂直居中)
<!-- html --> <div class="box"><img src="test.jpg" alt="" /></div>
//css .box { background: lightblue; line-height: 300px;font-size: 0; } .box img { vertical-align: middle; }
运行结果:
利用空白节点响应 "line-height" 形成高度撑开父容器,设置 { font-size: 0; } 是为了避免 "ex" 的影响,此时 "中线" 和 "基线" 就位于同一条线上,即父容器的垂直中点,为图片设置
{ vertical-align: middle; },将它的垂直中点对齐中线,也就是父容器的垂直中点(完)。