前言
一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊。。。。。。于是通过本篇来一探究竟:)
line-height到底有多height?
行距、行间距傻傻分不清
首先看看“有道词典”的解析!
Leading = Line Space + Font Size(即是 行距 = 行间距 + 字体大小)
Leading: 指相邻文本行间上一个文本行基线和下一文本行基线间的距离。
Line Space: 指相邻文本行间上一个文本行下行线(ascent)和下一文本行上行线(descent)间的距离。
而在一些面向普通消费者的软件中,Leading往往是指Line Space。Leading
在CSS当中,Leading就是指Line Space。而CSS属性line-height则是用于设置真实的Leading。参考
Still for each glyph, determine the leading L to add, where L = 'line-height' - AD
AD是指字形ascent和descent间的距离,即是font-size。
这里为更清晰地叙说,我将以广义Leading指代行间距,而狭义Leading则指代行距。
从W3C Rec中看出,line-height就是狭义Leading,而line-height的字面意思即为“行高”,推导结果CSS中行高即是行距。
这里我们了解到行高,行距和行间距的区别了。那接下来要介绍line-height的一个重要特性——垂直居中性。
line-height的垂直居中性
通过L = 'line-height' - AD
我们知道line-height=行间距+字形大小,字形大小我们可以通过font-size来设置,而line-height就更不用说了,而家问题是行间距所占的空间是怎样分配的呢?
方案1:不是说行间距就是上一行的descent到下一行的ascent间的距离吗?那直接分配到A位置就好了。
方案2:如果方案1的分配方案合理,那么分配到B位置就也是OK的。
方案3:一边倒的分配方案太不美观了吧!不如将行间距对半开,然后分别分配到上下两端不就OK了吗!
CSS采用的就是方案3。这是引用了Half-leading的概念,Half-leading = Leading/2.
Half the leading is called the half-leading. User agents center glyphs vertically in an inline box, which adds half-leading on the top and bottom. For example, if a piece of text is "12pt" high and the line-height value is "14pt", 2pt of extra space should be added: 1pt above and 1pt below the text (this applies to empty boxes as well, as if the empty box contained zero-height text).参考
在深入垂直居中性之前,我们先看一个容易引起误解的示例。(其实是我自己误解而已:()
<div id="container" style="border:solid 1px red;"><span style="background:blue;color:#fff;font-size:20px;line-height:60px;">center glyphs vertically in an inline box.</span></div>
不是说好了会垂直居中吗?你看字母x明明就在
div#container
中线的下方呢!
我们用空格符代替文字就可以看清楚了。
<div style="border:solid 1px red;"><span style="background:blue;color:#fff;font-size:20px;line-height:60px;"> </span></div>
“垂直居中”是指字形所在的盒子的垂直中线与line-height所占据的盒子的垂直中线重合,不是指字形的mean line和line-height所占据的盒子的垂直中线重合。
从
L = "line-height" - AD
可以知道行间距可能会负数,那么垂直居中性还有效吗?
答案是肯定的,L为负数时,Half-leading自然也是负数,只是上下两端从增加空间变为减少等量空间而已。不信你看
<body style="margin:0 10px;padding:0;">
<div style="position:relative;top:100px;font-size:90px;line-height:10px;background:yellow;"><span style="border:solid 1px red;line-height:10px;">x</span></div>
</body>
line-height属性
'line-height'
Value: normal | <number> | <length> | <percentage> | inherit
Initial: normal
Applies to: all elements
Inherited: yes
Percentages: refer to the font size of the element itself
Media: visual
Computed value: forand the absolute value; otherwise as specified
normal
Tells user agents to set the used value to a "reasonable" value based on the font of the element. The value has the same meaning as. We recommend a used value for 'normal' between 1.0 to 1.2. The computed value is 'normal'.
normal其实就是一个
<body style="font-family: Arial, Tahoma, Sans-serif;">
<div style="background:blue;color:#FFF;font-size:10px;">line-height-x-L</div>
<div style="background:blue;color:#FFF;font-size:40px;">line-height-x-L</div>
<div style="background:blue;color:#FFF;font-size:80px;">line-height-x-L</div>
<script type="text/javascript">
var els = document.getElementsByTagName('div')
for (var i = 0, len = els.length; i < len; ++i){
console.log(els[i].offsetHeight)
}
</script>
</body>
Chrome43的结果
14/10 = 1.4
45/40 = 1.125
92/80 = 1.15
average: 1.225 约为1.2
Firefox44.0.2
13/10 = 1.3
46/40 = 1.15
92/80 = 1.15
average: 1.2
IE9
11/10 = 1.1
46/40 = 1.15
92/80 = 1.15
average: 1.13333 约为1.1
通过小数据统计得出normal值的规律:
- 不同浏览器的normal值不相同;
- 同一个浏览器下,font-size值不同,normal值也会有变化;
- 同一浏览器下,font-size值相同,font-family值不同,normal值也会有变化;
- normal的平均值确实是在1.0~1.2之间(含两端),但具体到特定浏览器、font-family和font-size时,normal的实际值可能会大于1.2。
<length>
The specified length is used in the calculation of the line box height. Negative values are illegal.
设置固定值,单位可以是px、pt。好处是简单——设置是什么,line-height的实际高度就是什么。坏处是子元素默认情况下会继承父容器 的line-height属性,若子元素的font-size大于父容器的font-size属性值,那么子元素的文本行会十分密集,降低可阅读性。所以 我们一般采用相对font-size实际大小来设置line-height值的方式,如默认normal方式。
<percentage>
The computed value of the property is this percentage multiplied by the element's computed font size. Negative values are illegal.
既然采用
-
的参考系的确是font-size; - 子元素继承的是父容器实际的line-height值。也就是说父容器设置为
font-size:20px;line-height:200%;
,那么子元素继承来的line-height值为40px,而不是200%。因此又回到方式的问题上了。
<number>
The used value of the property is this number multiplied by the element's font size. Negative values are illegal. The computed value is the same as the specified value.
其实
line-height:1.2em;
和
line-height:1.2;
是等价的。若想将参考系改为根元素的font-size,则需要采用CSS3新增的
line-height:1.2rem
单位了。
根据WCAG2.0(万维网内容可存取性指南)规定“段落中的行距至少要1.5倍”,那么是否在body那设置一个
<style type="text/css">
body{
font-size: 16px;
line-height: 1.5;
}
h1 {font-size:32px;}
p {font-size:16px;}
#footer {font-size:12px;}
</style>
<h1>CSS魔法堂:深入理解line-height和vertical-align</h1>
<p>In my dual profession as an educator and health care provider, I have worked with numerous children infected with the virus that causes AIDS. The relationships that I have had with these special kids have been gifts in my life. They have taught me so many things, but I have especially learned that great courage can be found in the smallest of packages. Let me tell you about Tyler. </p>
<div id="footer">bed and whispered, “I might die soon. I’m not scared. When I die, please dress me in red. Mom promised she’s coming to heaven, too. I’ll be playing when she gets there, and I want to make sure she can find me.”</div>
看对于h1标题栏而言,行距太多了。于是得出如下配置:
body{line-height:1.5;}
h1,h2,h3,h4,h5,h6{line-height:1.2;}
vertical-align到底如何对齐呢?
下面我们稍微将line-height垂直居中特性中Leading为负数的示例代码修改一下,将font-size:90px;line-height:10px;
迁移到子元素中.
<div style="position:relative;top:100px;background:yellow;"><span style="border:solid 1px red;font-size:90px;line-height:10px;">x</span></div>
不是说垂直居中吗?这里就涉及到一个相对复杂的CSS垂直对齐规则——vertical-align。
注意:前方高能,需要IFC、line box作为前提知识。(可参考CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins)
vertical-algin属性
'vertical-align'
Value: baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage> | <length> | inherit
Initial: baseline
Applies to: inline-level and 'table-cell' elements
Inherited: no
Percentages: refer to the 'line-height' of the element itself
Media: visual
Computed value: forand the absolute length, otherwise as specified
<lenght>:设置相对于baseline的距离,正数表示位于baseline的上方,负数表示位于baseline的下方;
<percentage>:设置以line-height为参考系,相对于baseline的距离,正数表示位于baseline的上方,负数表示位于baseline的下方;
baseline:默认值。元素的基线与父元素的基线对齐;
top:把元素line box上边框对齐父元素的line box上边框;
text-top:把元素line box上边框对齐父元素的ascent(即content top edge);
super:升高元素的基线到父元素合适的上标位置;
middle:把元素line box中垂点与父元素基线 + x-height/2的高度对齐;
sub:降低元素的基线到父元素合适的下标位置;
text-bottom:把元素line box下边框对齐父元素的descent(即content bottom edge);
bottom:把元素line box下边框对齐父元素的line box下边框;
inherit:继承父元素的对齐方式。
怎么这么多规则要记啊?我记性不好难道到时还要挨个查吗?其实归纳一下就OK了!
- 对齐操作必定涉及操作元素和参考系元素,而vertical-align的值全是指参考系元素的位置,而操作元素则以baseline或linebox上中下作对齐;
- 默认对齐方式为baseline,数量值均是相对于baseline而言。
vertical-align仅对inline-level和table-cell元素有效
注意:vertical-align仅对inline-level和table-cell元素有效,下面示例无效是正常不过的。
<div>
<div style="float:left;font-size:20px;vertical-align:middle;">I'm former</div>
<div style="float:left;font-size:50px;vertical-align:middle;">I'm latter</div>
</div>
IE9+下的vertical-align属性值详解(以下内容均在Chrome43中测试)
1.默认对齐方式——baseline
<div style="font-size:14px;">
<span id="obj" style="font-size:40px;">line-height x vertical-align</span>
x for reference frame
</div>
这里x for reference frame作为参考系,而它的baseline就是
span#obj
所要对齐的baseline了。
那么在baseline的基础上的设置<length>和<percentage>
<div style="font-size:14px;">
<span id="obj" style="font-size:40px;vertical-align:10px;">line-height x vertical-align</span>
x for reference frame
</div>
<div style="font-size:14px;">
<span id="obj" style="font-size:40px;vertical-align:-10px;">line-height x vertical-align</span>
x for reference frame
</div>
<div style="font-size:14px;line-height:1;">
<span id="obj" style="font-size:40px;vertical-align:50%;">line-height x vertical-align</span>
x for reference frame
</div>
<div style="font-size:14px;line-height:1;">
<span id="obj" style="font-size:40px;vertical-align:-50%;">line-height x vertical-align</span>
x for reference frame
</div>
2.top——把元素line box上边框对齐父元素的line box上边框
我们将上面的示例稍微改一下
<span style="font-size:14px;">
<span id="obj" style="font-size:40px;vertical-align:top;">line-height x vertical-align</span>
x for reference frame
</span>
确实不同了,但这无法证明是元素的line box上边框对齐父元素的line box上边框哦。那么我们改改代码看看
<body style="margin:0 10px;padding:0;">
<div style="border:solid 1px blue;font-size:14px;line-height:1;">
<span id="parent" style="background:red;line-height:1;">
<span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;">line-height x vertical-align</span>
x for reference frame
</span>
</div>
</body>
通过
line-height:1
使line box与content box/area的高度一致,虽然
span#parent
和
span#obj
的上边框对齐,但还不能说明什么。
<body style="margin:0 10px;padding:0;">
<div style="position:relative;top:100px;;border:solid 1px blue;font-size:14px;line-height:1;">
<span id="parent" style="background:red;line-height:1;">
<span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;margin-top:100px;padding-top:100px;background-clip:content-box;">line-height x vertical-align</span>
x for reference frame
</span>
</div>
</body>
没有任何变化。那改变line-height又如何呢?
<body style="margin:0 10px;padding:0;">
<div style="border:solid 1px blue;font-size:14px;line-height:1;">
<span id="parent" style="background:red;line-height:2;">
<span style="display:inline-block;vertical-align:top;background:green;">
<span id="obj" style="background:yellow;font-size:40px;line-height:2;">line-height x vertical-align</span>
</span>
x for reference frame
</span>
</div>
</body>
为了让
span#obj
的Half-leading清晰可见,特意添加一个
display:inline-block
的inline box包裹着
span#obj
。而
span#parent
也增大了Half-leading的高度。现在可以我们清晰看到确实是
span#obj
的line box的上边框对齐父元素的line box上边框。(同理证明了
vertical-align:bottom
是把元素line box下边框对齐父元素的line box下边框;)
注意:chrome下若外层div不添加
font-size:14px;line-height:1;
属性,将导致span#parent上有条空白间隙
原因十分简单,那是因为
span#parent
的对齐方式是baseline,参考系是div的baseline,而div的line-height为normal,有空白间隙就是当然的事了。通过JS就可以看清楚了。
var div = document.getElementsByTagName('div')[0]
console.log(div.childNodes[0].nodeType) // 显示3,就是TextNode
其实除了在div上设置
line-height:1
之外,我们还可以在
span#parent
上设置
vertical-align:top
来解决。
<body style="margin:0 10px;padding:0;">
<div style="border:solid 1px blue;font-size:14px;">
<span id="parent" style="background:red;line-height:1;vertical-align:top;">
<span id="obj" style="background:yellow;font-size:40px;vertical-align:top;line-height:1;">line-height x vertical-align</span>
x for reference frame
</span>
</div>
</body>
3.text-top——把元素的line box上边框对齐父元素的ascent(即content top edge)
<body style="margin:0 10px;padding:0;">
<div style="position:relative;top:100px;border:solid 1px blue;font-size:14px;line-height:1;"> <span id="parent" style="background:red;line-height:2;">
<span id="obj" style="background:yellow;vertical-align:text-top;font-size:2px;line-height:1;">*</span>
x for reference frame
</span>
</div>
</body>
<body style="margin:0 10px;padding:0;">
<div style="position:relative;top:100px;border:solid 1px blue;font-size:14px;line-height:1;"> <span id="parent" style="background:red;line-height:2;">
<span style="display:inline-block;vertical-align:text-top;border-top:solid 2px green;">
<span id="obj" style="background:yellow;font-size:2px;line-height:2;">*******</span>
</span>
x for reference frame
</span>
</div>
</body>
4.middle——把元素line box中垂点与父元素基线 + x-height/2的高度对齐
<body style="margin:0 10px;padding:0;">
<div style="border:solid 1px blue;font-size:40px;line-height:1;">
<span id="parent" style="background:red;line-height:1;">
<span id="obj" style="padding-top:10px;display:inline-block;background:yellow;font-size:15px;line-height:1;vertical-align:middle;">*******</span>x for reference frame
</span>
</div>
</body>
注意
当元素的display:inline-block/inline-table
等对应的是atomic inline-level box时,其line box高度为margin box的高度。若元素对应的是inline box,则其最小高度为line-height,最大则由子盒子决定。
IE5.5~8下vertical-align属性值详解
由于我工作中没有适配IE8等历史浏览器的需求,因此详细内容请参考@张鑫旭的CSS vertical-align的深入理解(二)之text-top篇
简单来说IE5.5~IE8下vertical-align:text-top
是把元素的ascent对齐父元素的ascent(即content top edge)
真的掌握vertical-align了吗?
到这里理论部分已经介绍完了,是时候通过示例来验证自己了!
单行文字的垂直居中对齐
<style type="text/css">
.slma1{
border:solid 3px #888;
font-size: 14px;
line-height: 100px;
}
</style>
<p class="slma1">
字体大小14px
</p>
<style type="text/css">
.slma2{
border:solid 3px #888;
font-size: 14px;
line-height: 100px;
}
.slma2 i{font-style:normal;font-weight:bolder;vertical-align:middle;}
.slma2 span{font-size:30px;vertical-align:middle;}
</style>
<p class="slma2">
<i>* </i>字体大小为14px<span>字体大小为30px</span>
</p>
行数不固定的多行文字的垂直居中对齐
<style type="text/css">
.mlma1{
border:solid 3px #888;
font-size: 14px;
line-height: 100px;
}
.mlma1 span{
line-height: 1.5;
display: inline-block;
vertical-align: middle;
}
</style>
<p class="mlma1">
<span> 第一行文本<br/>the second one.</span>
</p>
大小不固定的图片的垂直居中对齐
<style type="text/css">
.a{width: 100px; height: 100px;}
.b{width: 80px; height: 80px;}
.c{width: 60px; height: 60px;}
.container{
background: #ccc;
line-height: 200px;
}
img{padding:5px;border:solid 1px blue;vertical-align:middle;}
</style>
<div class="container">
<img class="a" src="./john.png"/>
<img class="b" src="./john.png"/>
<img class="c" src="./john.png"/>
<img class="b" src="./john.png"/>
</div>