一、行高的定义
line-height(行高):两行文字基线之间的距离

1、什么是基线?
2、为何是基线?
3、需要两行吗?

1、什么是基线?
行高 line-height_行间距

 

我们上学的时候都用过,抄写英文字母的时候。其中有一条红线,这个红线就是基线,是为了写英文的时候对齐用的。
 
行高 line-height_行间距_02

 


2、为何是基线?
为什么不是底线,不是中线呢?因为基线乃*线定义之根本!

3、需要两行吗?
两行的定义已经决定了一行的表现!
行高 line-height_基线_03

 

如图,首先基线与基线之间的距离就是行高
 

接下来我们看看line-height:200px跟这个基线到底怎么纠葛,起作用的呢?
行高 line-height_firefox_04

 


然后我们脑补一下,如果行高为0会怎么样子呢,他会重合。

4、为何line-height可以让单行文本垂直居中?
首先真的垂直举重了吗?
行高 line-height_行间距_05

 

如图,会发现这个x跟这个破折号的中心并没有跟中线重合在一起。也就是实际上并没有完全居中的,只是看上去垂直居中了。
 
二、line-height与行内框盒子模型
1、什么是行内框盒子模型
所有内联元素的样式表现都与行内框盒子模型有关!例如浮动的图文环绕效果...
<p>这是一行普通的文字,这里有个<em>em</em>标签</p>
上面是一行普通的文字,有个em标签。但是,却包含了4种盒子。
1)、“内容区域”(content area),是一种围绕文字看不见的盒子。"内容区域"(content area)的大小与font-size大小相关。个人理解,可以是选中文字的时候,那一块区域
2)、“内联盒子”(inline boxes), “内联盒子”不会让内容成块显示,而是排成一行。如果外部含inline水平的标签(span,a,em等),则属于“内联盒子”。如果是光秃秃的文字,则属于“匿名内联盒子”;
3)、“行框盒子”(line boxes),每一行就是一个“行框盒子”,每个“行框盒子”又是由一个一个“内联盒子”(inline-boxes)组成
4)、<p>标签所在的“包含盒子”(containing box),此盒子由一行一行的“行框盒子”(line boxes)组成。

了解行内框盒子模型,对理解line-height有什么现实意义?

三、line-height对高度机理(机理是机制原理对简称)
先看一个小小的例子
<body>
  <p>这是一行普通的文字,这里有个<em>em</em>标签。</p>
  <script>
    console.log(document.querySelector("p").clientHeight);
    // mac chrome:22 firefox:23
    // windows chrome:21 ie:19 firefox:22
  </script>
</body>
那么这个元素高度是从何而来的呢?是不是由里面的文字撑开的?非也,是由line-height决定的
<style>
  .test1{
    font-size: 36px;
    line-height: 0;
    border: 1px solid #ccc;
    background: #eee;
    margin-top:50px;
  }
  .test2{
    font-size: 0;
    line-height: 36px;
    border: 1px solid #ccc;
    background: #eee;
    margin-top:50px;
  }
</style>
<body>
  <div class="test1">测试1</div>
  <div class="test2">测试2</div>
</body>
看这个demo,能看到test1文字长的很大,高度就是边框的高度,2px,test2有高度,文字没有,36px。所以内联元素的高度是由行高决定的

那么问题来了,line-height命名是两基线距离,单行文字哪来行高,还控制了高度?这就有点尴尬了。
1、行高由于其继承性,影响无处不在,即使单行文本也不例外;也就是说页面上所有元素,每个角落都有行高的。
2、行高只是幕后黑手,高度的表现不是行高,而是内容区域和行间距。
  只不过,正好... 内容区域高度+行间距 = 行高
   1)、内容区域高度只与字号以及字体有关,与line-height没有任何关系
   2)在simsun(宋体)字体下,内容区域高度等于文字大小值。
  simsun字体下:
  font-size + 行间距 = line-height
  那么什么是行间距呢?行间距 = 行高 - font-size
  把行间距上下拆分,就有了“半行间距”。
  总结:行高决定内联盒子高度;行间距墙头草,可大可小(甚至负值),保证高度正好等同于行高

那么问题来了,如果行框盒子里面有多个不同行高的内联盒子?由行高最高的那个盒子决定?似是而非!看上去好像是对的,其实是不正确的。
<body>
  <p>这是一行普通的文字,这里有个<em style="line-height: 80px;">em</em>标签</p>
  <script>
    console.log(document.querySelector('p').clientHeight);
  </script>
</body>
发现clientHeight正好是80px。如果是这个例子看,那句话是正确的。
<body>
  <p>这是一行普通的文字,这里有个<em style="line-height: 80px; vertical-align:40px;">em</em>标签</p>
  <script>
    console.log(document.querySelector('p').clientHeight);
  </script>
</body>
这个时候再来看一下这个行高的高度,91,不是80了。发生了一些变化,比预计的要高了。所以那句话是不准确的。那么vertial-align是个非常重要,也非常深的一个东西。等会讲这个东西。结论是91px不等于高度最高的内联元素。

前面讲的是单行文本的高度,如果是多行文本高度呢,多行文本的高度就是单行文本高度累加。

若行框盒子里面混入inline-block水平元素(如图片),高度如何表现呢?
 
四、line-height各类属性值
line-height支持的属性值大概这些
normal
<number>
<length>
<percent>
inherit
我们一个个来看一下

1)line-height:normal
默认属性值,跟着用户的浏览器走,且与元素字体关联。
比如我用的火狐,你用的chrome,这个normal的值可能就不一样
<body>
  <p>这是一行普通的文字,这里有个<em>em</em>标签。</p>
  <script>
    console.log(document.querySelector("p").clientHeight);
    // mac chrome:22 firefox:23
    // windows chrome:21 ie:19 firefox:22
  </script>
</body>
还有另外一种,字体不一样,normal的值也不一样
<body>
  <div style="font-family:雅黑">字体</div>
</body>
family不一样,normal的值也会不一样。

2)line-height:<number>
使用数值作为行高值。例如
line-height:1.5;
根据当前元素的font-size大小计算。

假设文字大小(font-size)20px.则实际的行高像素值是:
line-height = 1.5 * 20px = 30px

3) line-height:<length>
使用具体长度值作为行高值,例如
line-height: 30px;

4) line-height:<percent>
使用百分比作为行高值。例如
line-height:150%;
相对于设置了该line-height属性的元素的font-size大小计算。

假如文字大小(font-size)20像素,则实际的行高像素值是:
line-height = 150% * 20px = 30px;

5) line-height:inherit
行高继承: ie8+,行高天生好像就会继承,那么为什么还要这个继承呢?
input{ line-height: inherit; }
input框等元素默认行高是normal,使用inherit可以让文本框样式可控性更强。

此继承非彼继承。input的行高默认是normal,不是继承外面的,默认不受外面影响。这个时候可能需要继承一下

这里有一个有意思的问题
line-height:1.5,
line-height:150%,
line-height:1.5em
有什么区别?
我是这么认为的,从计算上来讲,是没有任何差别的。比如20px,计算出来,高度全是30px。差别在什么地方呢
应用元素有差别
1)line-height:1.5所有可继承元素根据font-size重计算行高;
2)line-height:150%/1.5em 当前元素根据font-size计算行高,继承给下面的元素;
这语言很苍白,不懂,看例子
<body>
  <div style="line-height:1.5; width:500px;">
    <span style="font-size:60px;">我的font-size为60px</span>
  </div>
  <div style="line-height:150%; width:500px;">
    <span style="font-size:60px;">我的font-size为60px</span>
  </div>
</body>
浏览器看会有什么不一样?上面的是90px,下面的是40px。上面的行高会重新计算扩大,下面的不会

body全局数值行高使用经验
body{ font-size:14px; line-height:?}
假如是博客,这种阅读为主的,行高至少1.5到1.6。如果主要是网页开发,面向用户的。一半匹配20px的使用经验-方便心算。
line-height = 20px / 14px = 1.42857
body{ font-size:14px; line-height:1.42857?}
这个很怪,火狐里面是19px;所以要向上取值
body{ font-size:14px; line-height:1.4286}
 
 
五、line-height与图片的表现
首先思考一个问题,行高会不会影响图片实际占据的高度?也就是行高从一百改成两百,这个图片占据的高度会不会变。不会变。
<p style="background:#eee"><img src="imgs/text.png" alt="" style="width:200px;"></p>
首先这么一张图片,会看到图片下面会有一段间隙,为什么会有间隙呢?这个时候在图片后面加一段文字,纹丝不动。没有任何变化。会发现图片的下边缘和文字的边缘是对齐的。这是为什么呢?因为默认是根据基线对齐的。这个时候改变行高,发现下边缘也变高了。
<body>
  <p style="background:#eee; line-height: 60px">
  <img src="imgs/text.png" alt="" style="width:200px;">
    <span style="display:inline-block; background:#fff;">图片高度177px,字体14px</span>
  </p>
</body>
会发现行高的高度就是文字的高度。因为要让文字根据基线对齐,所以下面的高度变高了。所以现在解释刚开始的下面的空隙。因为要把文字进行基线对齐,所以不得已,图片下面有空隙。那么为什么刚开始没有文字的时候,表现跟有文字一样呢。这里有个概念,叫做隐匿文本节点,这是自己的理解,就是里面好像有个文本,但是看不到,摸不到,js获取不到。

那么如何消除图片底部间隙?我们实际开发中是不需要的。
1、图片块状话-无基线对齐
img{ display: block; }
2、图片底线对齐
img{ vertical-align: bottom; }
3、行高足够小-基线位置上移
.box{ line-height:0; }

 

六、line-height的实际应用
像居中啊,边距什么的,上面都说过,就不探讨了。
1、大小不固定的图片,多行文字的垂直居中
<style>
  .box{
    line-height: 300px;
    text-align: center;
    background: #eee;
  }
  .box > img {
    vertical-align: middle;
  }
</style>
<body>
  <div class="box">
    <img src="imgs/text.png" style="width:200px" alt="">
  </div>
</body>
这个时候图片会近似的垂直居中,这里又用到了vertical-align;这个middle是基线1/2x的距离,下一章再具体研究下

2、多行文本水平垂直居中
<style>
  .box{
    line-height: 250px; text-align: center; background: #eee;
  }
  .box > .text{
    display: inline-block; line-height: normal; text-align: left; vertical-align: middle;
  }
</style>
<body>
  <div class="box">
    <div class="text">
      多行文字水平垂直居中实现的原理跟上一页图片的实现是一样的,区别在于要把多行文本所在的容器的display水平转换成
      和图片一样的,也就是inline-block,以及重置外部继承的 text-align 和 line-height属性值。
    </div>
  </div>
</body>
这里父元素text-align:center,和子元素vertical-align:middle跟图片居中是一样的。唯一不一样的就是要把text设置成inline-block;同时干掉父元素的line-height这些继承下来的东西。如果不干掉,三行文字都是250px。


 
接下来看几个行高的事例,产生的现象 
<style>
  span {
    background: red;
  }
  .c1 {
    line-height: 20px;
  }
  .c2 {
    line-height: 8px;
  }
  .c3 {
    line-height: 30px;
  }
  .c5 {
    line-height: 28px
  }
</style>
<body>
  <div>
    <span class="c1">inline box xfg中文</span>
    <span class="c2">inline box</span>
    <span class="c3">inline box</span>
    inline box
    <span class="c5">inline box</span>
  </div>
</body>

行高 line-height_firefox_06

它们的行高不一样,但是为什么渲染的高度是一样的

这个呢其实比较复杂,这个涉及到文字到排版,文字到排版中有几条线,上面叫做顶线,下面叫做底线,顶线和底线之间的区域叫做文本占据到区域。字母都会有一个基线,都是对齐的。这就是为什么行高不一样,但是却一样。第三个元素到行高是30。但是选中看高度还是22。那行高会决定什么呢?会决定它上下到多余的高度。我们选中div,发现刚好是30px。它会把外面的盒子撑起来。那么行高是由什么构成的。行高是由line-box(一行的高度)组成的。line-box是由inline-box组成的。inline-box的高度会决定line-box的高度

 

<style>
  .cc1 {
    font-size: 12px;
  }
  .cc2 {
    font-size: 18px;
  }
  .cc3 {
    font-size: 24px;
  }
</style>
<body>
  <div style="border:1px solid red">
    <span style="background:blue; color:#fff; font-size:20px; line-height:60px">
      居中xfg&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
    </span>
  </div>
  <div>
    <span class="cc1">第一段</span>
    <span class="cc2">第二段</span>
    <span class="cc3">第三段</span>
  </div>
  <div style="background:red">
    <span>文字</span>
    <img src="text.png" alt="">
  </div>
  <div>
    <div style="float:left">
      <span>第一段</span>
    </div>
    <div style="float:left">
      <span>第二段</span>
    </div>
  </div>
</body>
行高 line-height_基线_07

 

第一部分是为了大家看到的样子,div是没有定高的,里面有一个span。span是inline的元素。它也是没有定高的。因为span是inline元素,定高其实没用。它有一个背景blue。背景blue是根据字体大小来渲染的。底线和顶线之间。我们字体调大,背景也会变大。那我们的line-height是60px。60px实际上就是把整个div撑起来了。这个div是62,因为他有边框。这里有一个特性,就是行高比字体要大,要大的话,多余的高度会上下分布,让里面的inline元素垂直居中。这是一个非常重要的特性,如果要做垂直居中的话,用line-height来做就好了,而且在这种情况下都不用为div指定高度。

 行高 line-height_firefox_08

 第二部分我们看到字体的大小是不一样的。字体大小不一样,那么按照什么对齐呢。默认情况呢,是按照base-line,基线对齐。对大部分中文来说,底部基本上是基线对位置。如果要居中对齐怎么办。

行高 line-height_firefox_09

那我们就设置vertical-align:middle,居中对齐,三个部分都设置居中对齐。设置top就是根据顶线对齐。设置bottom就是根据底线对齐。这里根据顶线和底线对齐并不是根据文字都顶部和底部对齐。

 行高 line-height_垂直居中_10

第三部分有一个文本,有一个图片。然后会发现一个很奇怪的事情。这个图片下面有一段空白。有人说我是不想要这个空白的。那怎么办呢?首先他的原因是什么,原因是因为,img这个也相当于是一个inline的这样一个元素。inline的元素就要遵守行高的构成。他会按照base-line对齐。就是基线对齐。基线对齐的话,就意味着,基线到底线之间还是有一段空隙的。这是这个空隙产生的原因。那我们要去掉这个空隙怎么办?默认是按base-line对齐,base-line跟底线是有偏差的。这个偏差的大小视字体大小而定。如果是12px的大小,那么这个图片的空隙有可能就是3px左右。那么这就是经典的图片3px缝隙问题。这个问题怎么解决呢,很简单,默认是base-line。我们改成vertical-align:bottom,按底线对齐。这样缝隙就没有了