line box,inline box及vertical-align分析

一、适用元素

vertical-align适用于inline-level元素,即inline,inline-block或inline-table 。

二、inline与inline-block元素的外边缘和基线

inline元素的外边缘和基线

inline元素的外边缘是由它的line-height决定的。

line box,inline box及vertical-align分析

  • 红线:元素外边缘,即行高的顶部和底部边缘

  • 绿线:字体的高度。

  • 蓝线:基线。

上图中,左侧的那个,文本的行高设置为与字体大小相同的高度。上下两边绿色和红色的线均重合为一条线。中间的那个,行高是字体高的两倍。右边的那个,行高是字体高的一半。

inline-block元素的外边缘和基线

inline-block元素的外边缘就是它的margin-box的顶部和底部边缘。

line box,inline box及vertical-align分析

  • 红线:元素外边缘,即margin-box的顶部和底部边缘

  • 蓝线:基线。

上图中从左到右可以看到:一个inline-block元素里面有in-flow内容(一个“C”),一个inline-block元素有in-flow内容和overflow: hidden,一个inline-block元素没有in-flow内容(但是内容区域有高度)。

Inline-block元素的基线取决于元素是否具有in-flow内容

  • 有in-flow内容,inline-block元素的基线是普通流中最后一个内容元素的基线(例如左边那个)。对于最后一个元素,它的基线是根据它自己的规则确定位置的。

  • 有in-flow内容并且使用了值不是visible的overflow,基线就在margin-box的底部边缘那个位置(例如中间那个)。因此,它与inline-block元素的底部边缘一样。

  • 没有in-flow内容,基线也是在margin-box的底部边缘那个位置(例如右边那个)。

例如:下图中紫色为基线,两个span均是基线对齐。两幅图对比可以看出,随着第一个span元素中内容的增多,基线下移了。

<style type="text/css">
  .box {
    display: inline-block;
    width: 100px;
    height: 50px;
    border: 1px solid red;
  }
  </style>
 <div>
    <span class="box">士大夫和健康</span>
    <span class="box"></span>
  </div>

line box,inline box及vertical-align分析

<style type="text/css">
  .box {
    display: inline-block;
    width: 100px;
    height: 50px;
    border: 1px solid red;
  }
  </style>
 <div>
    <span class="box">士大夫和健康士大夫和健康</span>
    <span class="box"></span>
  </div>
 

line box,inline box及vertical-align分析

【注】:如果一个元素是浮动的(float:left/right),绝对定位的(position:absolute/fixed)或者是根元素(html),那么它被称之为流外的元素(out-of-flow)。如果一个元素不是流外的元素,那么它被称之为流内的元素(in-flow)。

三、content-area、inline box和line box

content-area:在非替换元素中,指元素中每个字符的字体大小串在一起所组成的框;在替换元素中,元素的固有高度加上任何margins, borders或padding。

inline box:每个元素的content-area加上leading。对于非替换元素,元素的inline box的高度等于line-height的值;对于替换元素,元素的inline box的高度等于该元素的固有高度加上任何margins, borders或 padding。

line box:一行就是一个line box。line box的边界是该行内inline boxes的最高点和最低点,即line box的顶部边缘是该行内最高inline box的顶部边缘,底部边缘是该行内最底inline box的底部边缘。

line box的文本盒和基线

文本盒可以当做是放在line box里面的没有任何对齐的行内元素。文本盒的高度等于它的父元素的字体大小。因此,文本盒只是把line box的无格式文本围起来了。这个盒子就是下图中用绿线标出来的那个。因为这个文本盒与基线相关联,当基线移动时,它也移动。

line box的基线无法定义。line box的基线被放在能够实现所有条件的地方。

line box,inline box及vertical-align分析
绿色:line box的文本盒。
红色:line box的顶部和底部边缘。
蓝色:基线。
灰色:文本元素的区域。

查看line box基线的方法:在行的开头增加一个字符,就像上图中增加的“X”。它默认地坐在基线上。line box是垂直对齐发生的区域。line box有一条基线,一个文本盒和一个顶部和底部边缘。

line box高如何计算

  1. 当一行中仅有行内不可替换元素,且这些元素都是相同的 font-size、line-height和vertical-align。则content-area=font-size, line-box的高=line-height。

  2. 当一行中包含行内元素,这些元素包括可替换和不可替换,这些元素有不同的 font-size和 line-height。则按以下方式计算:content-area的高由每个不可替换元素的font-size,以及替换元素的固有高度和任何padding, borders,或margins决定。leading应用于每一个元素,一半放在顶部,一半放在底部。line box的顶部边缘是该行内最高inline box的顶部边缘,底部边缘是该行内最底inline box的底部边缘。

例如:

<P style="line-height: 12pt; font-size: 12pt;">
      <A style="font-size: 128pt;">anchor</A> angry text
      <B style="vertical-align: top">bold</B>
</P>

anchor的content-area是128pt,但是他的inline box是12pt。假设字体是Helvetica,那么

descent : 128pt*219/1000=28pt
ascent :  128pt*781/1000=100pt
halfleading : (12pt-128pt)/2 = -58pt
inline box的top:100pt-58pt=42pt
inline box的bottom:58pt-28pt=30pt

所以这个inline box的top为基线上42pt,bottom为基线上30pt。同理可得匿名文本angry text的top是基线上10pt,基线下2pt。所以line-box的高是44pt:基线上42pt,基线下2pt。

line box,inline box及vertical-align分析

将angry text文本去掉,会发现父元素P高度不变。
原因:根据W3C规范
在由inline-level元素组成的块容器元素中,line-height确定了该元素内部line boxes的最小高度。这个最小高度由基线上的最小高度和基线下的最小深度组成,就像每个line box都是由宽度为零,拥有父元素的font-size和line-height的inline box(假想元素)开始的。
我的理解是line box是在这个假想元素的基础上往两边延伸。例如:

    <P style="line-height: 44pt; font-size: 12pt;">
      <A style="font-size: 128pt;">anchor</A>
    </P>

line box,inline box及vertical-align分析
p元素中只有anchor文本,但是该文本的inline box的top为基线上42pt,bottom为基线上30pt。所以line box的top为基线上42pt,而line box的bottom不是基线上的30pt,而是原先假想元素的基线下的最小深度(即上图中蓝线到最后一条红线的距离)。

因此,即使没有angry text文本,基线下也会有一个最小深度,所以导致P元素的高度不变。

注:

  1. 例子中计算Helvetica字体用的219和781是修改过的数据,只是为了让数据好看点,实际应该是接近于225和775。

  2. leading = line-height - font-size。
    其中一半leading加到文字上方,另一半leading加到文字下方。

  3. line box,inline box及vertical-align分析

  4. line-height对可替换元素的inline box没有影响,但是当该元素的vertical-align值为百分比时,是有影响的。

四、Vertical-Align的值

line box,inline box及vertical-align分析

  • baseline:元素的基线在line box的基线顶部。

  • sub:元素的基线移动到line box基线以下。

  • <percentage>:元素的基线通过与line-height相关联的percentage ,相对于line box的基线进行偏移。

  • <length>:元素的基线通过绝对长度相对于line box的基线进行偏移。

line box,inline box及vertical-align分析

  • middle:元素顶部和底部两者间的中点与line box的基线加上二分之一的x-height对齐。

line box,inline box及vertical-align分析

  • text-top:元素的顶部边缘与line box的文本盒的顶部边缘对齐。

  • text-bottom:元素的底部边缘与line box的文本盒的底部边缘对齐。

line box,inline box及vertical-align分析

  • top: 元素的顶部边缘与line box的顶部边缘对齐。

  • bottom:元素的底部边缘与line box的底部边缘对齐。

五、Vertical-Align的诡异行径

Line Box的基线的移动

例如:

div {
    font-size: 16px;
    line-height: 1;
    background-color: #eee;
    margin-top: 10px;
  }
  
  .tall-box {
    border: 1px solid red;
    width: 40px;
    height: 40px;
    display: inline-block;
  }
  
  .short-box {
    border: 1px solid black;
    width: 40px;
    height: 10px;
    display: inline-block;
  }
  <div>
    <span class="tall-box" style="vertical-align: text-top;">    </span>
    <span>Exg</span>
    <span class="short-box"></span>
  </div>

line box,inline box及vertical-align分析

若将tall-box的vertical-align变成top,得下图

line box,inline box及vertical-align分析

从上下两幅图对比可以看出,随着vertical-align从text-top变成top,Exg往上移,导致字体高超出了父div的边界。这是由于line-height的高小于字体高。

若将第一个图中的父div的line-height变为2,使Exg的line-height值大于字体原本的高度,则得下图。从图中可以看到,红框下降了,父div的高度变高了。这是由于红框是text-top对齐,由此可知道基线位置在哪里。而基线位置的确定可以确定Exg和黑框的位置。而line box的顶部边缘是该行内最高元素的顶部边缘,这时候最高的是Exg,因此可以看到红框下降,父元素变高了。

line box,inline box及vertical-align分析

Inline-Level元素的底下间隙

<ul>
  <li class="box"></li>
  <li class="box"></li>
  <li class="box"></li>
</ul>

<style type="text/css">
  .box{
    display: inline-block;
   }
</style>

line box,inline box及vertical-align分析

可以看到li元素底下有间隙。

间隙产生的原因:因为列表项位于基线上,而在基线下是放文本descenders空间。

取消该间隙的方法:

  1. 设置li元素vertical-align: middle;

  2. 在li元素内添加内容。因为内容会将基线上移。

参考自:
inline-format
【译】Vertical-Align: All You Need To Know

上一篇:114.关于前端的vertical-align详解


下一篇:CSS中怎么设置元素水平垂直居中?