css行高line-height的一些深入理解及应用

这篇文章发布于 2009年11月28日,星期六,02:51,归类于 CSS相关。 阅读 548890 次, 今日 26 次 127 条评论

 

补充于2017年12月31日:写本文时本人尚年轻,很多措辞和观点并不严谨,内容仅供参考。更体系更深入的理解在我的《CSS世界》这边书中有详细阐述。

一、前言

前两天在腾讯ISD团队博客上看到一篇翻译的文章“深入理解CSS行高”(原地址失效已久),是个不错的文章,学到了不少东西,建议您看看。

这里,我也要讲讲我对line-height的一些理解,所讲解的东西绝大多数与上面提到的“深入理解css 行高”是不重复的,可以说是补充或是另外一个角度的思考。另外,将结合实际,展示line-height的一些特性和一些常见应用,帮助您对CSS行高line-height的理解。所讲述的并不一定都是正确的,欢迎指正欢迎交流。

二、一些字面意思

“行高”顾名思意指一行文字的高度。具体来说是指两行文字间基线之间的距离。基线实在英文字母中用到的一个概念,我们刚学英语的时使用的那个英语本子每行有四条线,其中底部第二条线就是基线,是a,c,z,x等字母的底边线。下图的红色线即为基线。

英语本子的各条线

vertical-align中有top,middle,baseline,bottom与之是由关联的,但具体细节如何,浏览器差异怎样,我还不是很清楚。

但是由于中文跟英文长得不一样,所以基线的说法就像老太太穿线——对不上眼。您理解为底线之差也不为不可。只是定义一回事,表现则另一回事。

三、line-height与line boxes高度

CSS中起高度作用的应该就是height以及line-height了吧!如果一个标签没有定义height属性(包括百分比高度),那么其最终表现的高度一定是由line-height起作用,即使是IE6下11像素左右默认高度bug也是如此。待我慢慢叙来。

先说一个大家都熟知的现象,有一个空的div<div></div>,如果没有设置至少大于1像素高度height值时,该div的高度就是个0。如果该div里面打入了一个空格或是文字,则此div就会有一个高度。那么您思考过没有,为什么div里面有文字后就会有高度呢?

这是个看上去很简单的问题,是理解line-height非常重要的一个问题。可能有人会跟认为是:文字撑开的!文字占据空间,自然将div撑开。我一开始也是这样理解的,但是事实上,深入理解inline模型后,我发现,根本不是文字撑开了div的高度,而是line-height!要证明很简单(如下测试代码):

CSS代码:

.test1{font-size:20px; line-height:0; border:1px solid #cccccc; background:#eeeeee;}
.test2{font-size:0; line-height:20px; border:1px solid #cccccc; background:#eeeeee;}

HTML代码:

<div class="test1">测试</div>
<div class="test2">测试</div>

结果如下图(windows IE6浏览器下):

行高撑开高度还是文字撑开高度测试结果

结果是如此的显而易见,test1 div有文字大小,但行高为0,结果div的高度就是个0;test2 div文字大小为0,但是有行高,为20像素,结果div高度就是20像素。这就说明撑开div高度的是line-height不是文字内容。

到底这个line-height行高怎么就产生了高度呢?在inline box模型中,有个line boxes,这玩意是看不见的,这个玩意的工作就是包裹每行文字。一行文字一个line boxes。例如“艾佛森退役”这5个字,如果它们在一行显示,你艾佛森再牛逼,对不起,只有一个line boxes罩着你;但“春哥纯爷们”这5个字,要是竖着写,一行一个,那真是够爷们,一个字罩着一个line boxes,于是总计五个line boxesline boxes什么特性也没有,就高度。所以一个没有设置height属性的div的高度就是由一个一个line boxes的高度堆积而成的。

其实line boxes不是直接的生产者,属于中层干部,真正的活儿都是它的手下 – inline boxes干的,这些手下就是文字啦,图片啊,<span>之类的inline属性的标签啦。line boxes只是个考察汇报人员,考察它的手下谁的实际line-height值最高,谁最高,它就要谁的值,然后向上汇报,形成高度。例如,<span style="line-height:20px;">取手下line-height<span style="line-height:40px;">最高</span>的值</span>。则line boxes的高度就是40像素了。

四、行高的垂直居中性

行高还有一个特性,叫做垂直居中性。line-height的最终表现是通过line boxes实现的,而无论line boxes所占据的高度是多少(无论比文字大还是比文字小),其占据的空间都是与文字内容公用水平中垂线的。还拿上面这张图来说吧。

行高撑开高度还是文字撑开高度测试结果

看test1的结果,此时line boxes的高度为0,但是它是以文字的水平中垂线对称分布的。这一重要的特性可以用来实现文字或图片的垂直居中对齐。

五、在单行或多行或图片垂直居中实现上的应用

您可以狠狠地点击这里:行高实现单行和多行文字垂直居中demo

1、单行文字的垂直居中对齐

网上都是这么说的,把line-height值设置为height一样大小的值可以实现单行文字的垂直居中。这句话确实是正确的,但其实也是有问题的。问题在于height,看我的表述:“把line-height设置为您需要的box的大小可以实现单行文字的垂直居中”,差别在于我把height去掉了,这个height是多余的,您不信您可以自己试试。

2、多行文字的垂直居中

要实现高度不固定的文字垂直居中使用padding就好了。对于高度固定的div,里面文字单行或多行显示,字体大小有大有小的情况怎么办呢?方法之一就是借助于line-height

下图为demo页面的截图批注图:
多行文字垂直居中原理演示

正如上面所说,line boxes的高度取决于它的下属职员的最高高度。而这个高度由一个不占据任何空间的空格完成,方法即使设置font-size0line-height为所需要的高度。同时,我们为了分隔line boxes,同时要保持在一行上,需要设置display属性值为inline-block。如下代码,有别于demo:

CSS代码:

.mulit_line{line-height:150px; border:1px dashed #cccccc; padding-left:5px; font-size:0;}
.mulit_line span{display:-moz-inline-stack; display:inline-block; line-height:1.4em; vertical-align:middle;}
.mulit_line i{width:0; display:-moz-inline-stack; display:inline-block; vertical-align:middle;}

感谢小西的提醒,下为修复IE8问题后的代码:

.mulit_line{line-height:150px; border:1px dashed #cccccc; padding-left:5px;}
.mulit_line span{display:-moz-inline-stack; display:inline-block; line-height:1.4em; vertical-align:middle;}
.mulit_line i{width:0; display:-moz-inline-stack; display:inline-block; vertical-align:middle; font-size:0;}

html代码:

<p class="mulit_line">
    <span style="font-size:12px;">这里是高度为150像素的标签内的多行文字,文字大小为12像素。<br />这里是第二行,用来测试多行的显示效果。</span><i>&nbsp;</i>
</p>

效果如上批注图。已通过IE8以外的主流浏览器的兼容性检测。以前曾见过说IE8的line-height有些问题,如果谁发现IE8下有问题,欢迎指出,不甚感谢。

3、图片的垂直居中

您可以狠狠地单击这里:行高使图片垂直居中显示demo

此方法在“大小不固定的图片、多行文字的水平垂直居中”一文中的最后补充内容里已经详细讲解了。这里不多说了。

//zxx:之前未能在IE8下测试,现发现此方法不仅在Opera下有问题,在IE8下也是表现欠佳。所以仅仅使用line-height的垂直居中法有待斟酌,或许要使用与上面多行文字垂直居中的同样的方法来实现图片垂直居中的效果。

六、行高在文章显示中的应用

一般社交型的网站都会有发博文或写日志的功能,其中发表后的文章显示也是有学问的,其中之一就是line-height行高。

首先要知道行高的几种表示方法:px/em,或normal,或百分值,或数值,或inherit继承。

在显示文章的box里,px的表示方法首先是要被淘汰的。因为文章里面的文字是有大有小的,使用px定值,由于继承性,无法实现根据文字大小自动调整间距,会出现大号文字重叠的现象。normal也是不行的,一般文章显示最好是650像素的宽度,1.5倍的行距较好。一般浏览器的normal值在1~1.2之间,使用normal必然文字间距过小,阅读吃力。百分值也有继承性,但是有个很搓的办法可以实现文字间距自动适应于文字的大小,那就是使用*通配符,例如:

.article_box *{line-height:150%;}

就不会出现文字重叠的情况了。网易博客就是使用的这个方法,下图为证:

网易博客使用百分比加通配符实现行高自适应

为什么说这个方法搓呢,使用*通配符大大增加了CSS的渲染,效率低,而且有更好的方法,就是使用数值。150%虽然和1.5在值上是一样的,但是它们也是有差别的,差别在于继承性,使用百分比会计算line-height的值,然后以px像素为单位继承下去,而1.5则是先继承1.5这个值,遍历到了该标签再计算去line-height的像素值。所以同样的效果只需要下面CSS就可以实现了。

.article_box{line-height:1.5;}

七、使用行高代替高度避免haslayout

在某些情形下,line-height可以和height互换,因为实现的效果一样。都能撑开一个高度,然而这两个CSS属性有一个较隐蔽的差异,就是使用height会使标签haslayout,而使用line-height则不会。以前只有IE6的时候曾流行使用height清除浮动,就是利用了IE下height使haslayout的属性。但有时候,haslayout并不需要,反而要避免。

读过我前面有关自适应按钮文章的人可能会发现我使用了line-height代替了height,其原因在于:IE6,IE7下,类似inline-block属性的元素里如果有block属性的元素,如果该block haslayout,则该标签会冲破外部inline-block的显示而宽度100%显示,从使按钮自适应文字大小的效果失效,解决方法就是使用line-height代替height

height与line-height在IE6下区别

上图中第一个标签使用height定高,结果宽度直接100%显示;第二个标签使用line-height定高,结果很规矩,自适应与内部文字大小。其代码如下:

CSS部分:

.out{display:inline-block; background:#a0b3d6; margin-top:20px;}
.in1{display:block; height:20px;}
.in2{display:block; line-height:20px;}

HTML部分:

<span class="out">
    <span class="in1">height:20px;</span>
</span>
<span class="out">
    <span class="in2">line-height:20px;</span>
</span>

八、结语

很多关于line-height的基础的知识这里并没有详细讲述,本文一开始提到的腾讯ISD团队的那篇关于行高的文章是不错的,对于了解line-height的一些特性及inline box模型很有帮助。本文更多的是讲述自己对于line-height的一些理解,简述了我使用line-height的一些经验。由于都是个人的些东西,加上本身自己的资历有限,所以可能会出现一些错误,一些遗漏之处等,还望了解。欢迎指正。要是能对您的学习有所帮助就再好不过了。

(本篇完)

分享到:


发表评论(目前127 条评论)

  1. 小兵说道:

    为什么不添加 
    ie6中父级行高就无效了

  2. Hector说道:

    深入理解行高链接失效 (-__-)~~~

  3. 姚伟说道:

    你好,您在文章中提到的 腾讯ISD团队博客文章 深入理解css 行高,链接无效了,搜索了很久也没有找到这篇文章的转载或者快照,请问您知道在哪里还可以看见这篇文章吗?感谢

  4. 耳朵说道:

    一行中文字大小不同的话要怎么垂直居中呢?

  5. zk说道:

    大哥你提到的“深入理解css 行高”一文的链接无效了,可以提供个有效的链接吗

  6. font-size:0; line-height:20px;在IE8+里面高度也是0啊说道:

    font-size:0; line-height:20px;在IE8+里面高度也是0啊

  7. sumizu说道:

    “其实line boxes不是直接的生产者,属于中层干部,真正的活儿都是它的手下 – inline boxes干的”
    这里最后一个 inline boxes 应该是 inline box 吧?

  8. 路过说道:

    2013年07月31日 17:24
    刚刚发现如果文字不是用br换行,而是达到一定长度自然换行的话,居中效果就会失效。这是怎么回事?
    这个问题直接说明了这篇文章就不该被写出来,基本没什么价值

  9. 路过说道:

    font-size:0; line-height:20px;在IE8+里面高度也是0啊

  10. 亦梦薇说道:

    font-size:0的话文字会显示不出来的

  11. clement说道:

    我也迟职回图书馆闭关修炼,以前只懂后台,不懂前台。在学习前端的时候,我一直搞不清楚它们之间的关系,今天看了你这篇文章,感觉顿时明了。你好厉害你对每个知识点都了解得这么透彻。

  12. fmz_luffy说道:

    迫切的想请问一下 ie8下select里面的文本内容不居中该怎么办

  13. 李宁说道:

    您好,想请教下这篇文章中的demo里为什么要再写一个 呢,我测了下不要这个空标签显示效果也是垂直居中正常的。
    我读了好几遍,觉得“正如上面所说,line boxes的高度取决于它的下属职员的最高高度。而这个高度由一个不占据任何空间的空格完成,方法即使设置font-size为0,line-height为所需要的高度。”这个可能是解释,但是不太懂。
    还有您说的关于腾讯翻译的行高那篇文章,链接已经失效了。百度 一时也没有搜到,在哪里还能找到吗 ?

    • 刺客说道:

      我也发现了这个问题,我发现应该是前面的line-height: 150px在起作用,后面的不起作用

  14. ablian说道:

    张兄您好。
    我发现微信自带的webview中,line-height 设置成 height的高度,却不能实现单行文字垂直居中。这是为何?

  15. 小明说道:

    张总 有问题直接找张总 其他的鸟都不鸟 恩人 我要为你生猴子

  16. Lilian说道:

    首先感谢张老师无私奉献。拜读了张老师的这篇文章,关于五中 2、多行文字的垂直居中 有一些疑问。直接拷贝代码后,在谷歌版本 39.0.2171.71 m中p的最终行高测量下来是152px,ff34.0下p的行高为151px,IE下p的行高150px。(测量都不含外边框2px)。调试了下,感觉像是中的vertical-align:middle撑开了谷歌下的2px,设置为vertical-align:bottom后,测量p的行高为150px,但是文字似乎没有居中,上面空白比下面空白多了2px。
    以上不晓得是不是只有我这里是这个样子。

    更正下,感觉像是标签中

  17. riophae说道:

    文字垂直居中那个 demo 在 IE10 下有问题..

  18. enforceway说道:

    ‘多行文字的垂直居中’的例子中,貌似最终针对文字或者inline-leve级别的标签最好了,如果不是文字而是个float left或者float right的li标签,不太容易让li标签在最右侧出现。

  19. 叫我小徐说道:

    之间看博主的关于按钮自适应的文章,当我用height去设置的时候,ie6出现的问题让我始终想不明白!今天在这里找到了答案,心里的一块石头落下来了。THX

  20. 华中科技大学 常明说道:

    希望博主写篇关于hasLayout的文章。

  21. francis说道:

    font-size:0 刚在chrome里面测试了,文字不显示,况且也不是“测试”啊 还以为有多nb呢,看来中国还是靠忽悠混的人比较多啊,呵呵~

    哈哈 看来ie都有这个问题啊 啊哈哈 这真是臭大了哦,lz出来解释吧。还以为腾讯的人有多nb呢 还200k哈哈~

    哦 不好意思 看错了 哈哈 那你也写一个 “测试1” 和 “测试2” 啊 呵呵 错怪lz了 sorry呵呵~:(

    —by 前端新人中的新人

    • small_bear说道:

      这么冲动?

    • rg说道:

      呵呵,刚开始我也看错了,不显示的 问题。还是把文章读完比较好

    • Joyce说道:

      首先这篇文章写于09年,已经过去近5年。在浏览器频繁更新的年代,即使有错误也是可以理解的。就算在当时文章所说的不对,也应该就技术本身进行讨论。不要用什么“忽悠”、“还以为腾讯的人有多nb呢 还200k哈哈~”等词,来表达你藐视的节操。其次,能够进入腾讯这样的大公司,都是有一技之长的,面试一般会有好几轮,不是靠运气和忽悠就能过关的。最后,虽然你表示你错了,但是仍然不能掩饰你肤浅、浮躁的本质。
      ps:以楼主的水平,年薪200K真的是太太太少了。

    • yao说道:

      作为一个前端新人中的新人,还对前辈如此不尊重。实在是无力吐槽啊…哎林子大了,什么鸟都有

    • zzj说道:

      逗逼

  22. darth说道:

    你好,test2中,font-size:0; line-height:20px; 在IE8、9、10是无法撑开的20px的高度的,不知道你有没有发现这个问题?(PS:我的浏览器是64bit的win7)

    • yxj说道:

      我也发现这个问题了,font-size:1,只要不是为0都可以,空格反正看不见,是个字符而已,字体大小无所谓的,感觉这个好像跟chrome限制字体大小类似的。按照博主的理论line-height:150px不应该应用在.mulit_line上,最好放在.mulit_line i 里面。

  23. 叫我小T说道:

    刚刚发现如果文字不是用br换行,而是达到一定长度自然换行的话,居中效果就会失效。这是怎么回事?

  24. ifishing说道:

    测试页面中IE8下多行文字居中对齐不起作用,解决方案将你的doctype改为 <!doctype html> 即可。

  25. markleung说道:

    感谢!

  26. 嚯哈说道:

    为什么行高和字体设置一样大时,行与行之间还会有间隙呢?

  27. 桃桃说道:

    不明白为什么增加了就会显示正常取消了test就变成了子元素的line-height了

  28. Cheney说道:

    关于多行居中,可以改进下,不设置内部的inline box,而是直接设置块级容器的line box,可以达到同样的效果:

    我是一段文字我是一段文字我是一段文字我是一段文字我是一段文字

  29. F团J说道:

    请问在一个固定的框中如何让行高随着行数的变化而变化

  30. fsy说道:

    在IE8中测试 也没有高度

  31. 胖徐说道:

    br 能不能不参与line-height设置啊?
    若line-height设置25px,br产生的换行会很高

  32. view说道:

    是在input里面设置height.

  33. view说道:

    发现一个问题,也是关于IE8的,就是在设置了height后.line-height再次设置,似乎对IE8 是没有作用的,如何解决这个问题?

  34. BlwooSky说道:

    如果元素内有图片或表单元素的话,在ie6下设置行高就没有效果了。

  35. 荡悠生活说道:

    设置一个height是完全有必要的,主要是针对IE8 IE9 ,具体为什么,还在研究。

  36. 掏你屋说道:

    在input标签中用class设置line-height无法生效是什么原因,求大神赐教~~~~

  37. lcat说道:

    当子元素浮动之后,ie678下浮动的子元素行高会出错,不知道这个要如何解决???

  38. x说道:

    回复 9 L 见 15 L

  39. x说道:

    发现是需要给 i 标签一个 width:0;visibility:hidden; 属性就可以,font-size 可以随便用。。。

  40. 单行的行高说道:

    “行高”顾名思意指一行文字的高度。具体来说是指两行文字间基线之间的距离。

    如果只有一行文字,又没有设置line-height,行高怎么计算?

  41. 夜之花狸说道:

    对于多行文字居中,我有点不理解。
    1. 博主您说
    【line boxes的高度取决于它的下属职员的最高高度。
    而这个高度由一个不占据任何空间的空格完成,方法即使设置font-size为0,
    line-height为所需要的高度】

    空格的font-size:0; 可是同行的内的匿名inline-boxes的font-size:12px;
    这个高度理应有匿名inline-box来承担啊。这点不是很理解
    ===========================================================
    2 .两行的文字理应有两个line-box,各自高度应为的line-height 1.4*12px决定呢 还是的line-height:150px来决定呢?
    ===========================================================
    3. display:inline-block;是不是将两行文字合成一个line-box来对待了?

  42. 晓丽均说道:

    个人很不赞同博主所说的 关于css 渲染速度效率之类的问题,因为资源的下载时间比渲染的时间要长的多,渲染所需的时间微乎其微,毕竟长网页少之又少,IE浏览器里面标签上网以后不加样式就已经有些卡顿了

  43. 东城说道:

    多行文字的垂直居中,IE8下确实有问题,不知道博主是怎么测试的。。。!

  44. xmlovedoudou说道:

    “test1 div有文字大小,但行高为0,结果div的高度就是个0;test2 div文字大小为0,但是有行高,为20像素,结果div高度就是20像素。这就说明撑开div高度的是line-height不是文字内容。”

    楼主根据实例总结的这句话,我也可以改成这样,完全就跟你说的不一致了。如下:
    文字也是有大小的(包含了高度),font-size设置的多少决定了占多少容器的空间。那么决定容器空间高度的无非是两个因素来起作用的:
    1.line-height.
    2.height.

  45. yangyang说道:

    多行文字垂直居中的方法。。。貌似在IE8和IE9之下没法成功啊。。别的浏览器都不错,但是惟独IE8和IE9之下。。难道是DIV没有撑开?

  46. 答案说道:

    博主的文章和细致,写一篇文章肯定要花好多时间和精力.

  47. Qiangfan168说道:

    看了很有收获,谢谢作者的无私奉献。

  48. 小子说道:

    你这篇文章中的图片垂直居中在IE8下是不起作用的

  49. 小西说道:

    使用“2、多行文字的垂直居中”中的代码发现有浏览器不兼容的问题,仅测试了IE8、FF3、IE6、Safari,IE8显示如同,其它浏览器则显示不一样,问题很严重啊~

  50. 开心凡人说道:

    周末到处看一看,这里挺好呵呵