行内格式化上下文中的各种高度计算

行内格式化上下文中的各种高度计算

2015/10/11 · CSS · 高度

原文出处: HaoyCn   

前言碎碎语:标题问题在昨天困扰了笔者很久很久,早上把问题提到了各网络也暂时没有回复。因为明天要早起飞异地参加一场校招面试,笔者还是很紧张的,但奈何问题不解决寝食难安……所以还是卯起劲重新思考这个问题,算是暂时有了一个自己比较认可以及清晰的答案,与各位读者分享。如您有不同观点想法意见建议,恳请斧正!

正式探讨之前,我们观察一个现象(在 Chrome 下的表现,其他浏览器下的表现和计算可能有细微差别):

图片 1

上图对应的 HTML 是(之后的探讨均基于此):

<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Line Height</title> <style> body { margin: 0; font: 32px/1 'Microsoft YaHei'; } div { width: 400px; margin: 30px auto; outline: 1px solid black; background: #008E59; } img { height: 80px; margin-top: 10px; } </style> </head> <body> <div> <span>Some Text</span> <img src="picture.jpg" alt=""/> </div> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Line Height</title>
<style>
body {
    margin: 0;
    font: 32px/1 'Microsoft YaHei';
}
div {
    width: 400px;
    margin: 30px auto;
    outline: 1px solid black;
    background: #008E59;
}
img {
    height: 80px;
    margin-top: 10px;
}
</style>
</head>
<body>
    <div>
        <span>Some Text</span>
        <img src="picture.jpg" alt=""/>
    </div>
</body>
</html>

我们来计算下 DIV 和 SPAN 的高度

JavaScript

document.getElementsByTagName('div')[0].offsetHeight //93 document.getElementsByTagName('span')[0].offsetHeight //42

1
2
3
4
document.getElementsByTagName('div')[0].offsetHeight
//93
document.getElementsByTagName('span')[0].offsetHeight
//42

对于此图,笔者产生如下疑问:

  • line-height  为 32px,为何 SPAN 的高度为 42px?
  • DIV 的高度 93px,比 IMG 高度加外边距 90px 以及 SPAN 高度 42px 都要大,如何计算的?
  • 图片和文本下的空白(即便没有文本一样存在)是如何产生的?

假设我们把 IMG 删除,HTML 部分改为:

<body> <div> <span>Some Text</span> </div> </body>

1
2
3
4
5
<body>
    <div>
        <span>Some Text</span>
    </div>
</body>

此时来计算:

JavaScript

document.getElementsByTagName('div')[0].offsetHeight //32 document.getElementsByTagName('span')[0].offsetHeight //42

1
2
3
4
document.getElementsByTagName('div')[0].offsetHeight
//32
document.getElementsByTagName('span')[0].offsetHeight
//42

新问题又来了:

  • DIV 的子元素高度为 42px,为何没有“撑起” DIV 的高度?

以上问题就是本文要探讨的了。覆盖了五个知识点:

  1. 行内盒(或行内不可替换元素)的高度
  2. 行内可替换元素的高度
  3. 行盒的高度
  4. 行距与行高
  5. 建立行内格式化上下文的块盒的 auto 高度

所以在探讨之前,笔者已假设您知道这些概念:行内盒、行内不可替换元素、行内可替换元素、行盒、行内格式化上下文。如果您还有点不清楚,我们可以快速补习下:

可替换元素、不可替换元素

简单地讲,可替换元素是指须根据其标签和属性来决定具体显示内容的元素,如本文中会探讨的 IMG 元素,其具体显示内容由  src 等属性决定; 不可替换元素则是内容直接呈现的元素。如本文会探讨的 DIV 和 SPAN 等。

块盒

此概念是块格式化上下文的内容,要解释起来就更复杂啦,笔者粗陋地给您一个描述:块盒通常是  display: block 的不可替换元素。

行内级元素、行内级盒、行内盒、行内格式化上下文

display: inline|inline-table|inline-block  产生行内级元素。行内级元素生成行内级盒,而这些盒会参与行内格式化上下文。

display 值是  inline 的不可替换元素会生成一个行内盒。

不是行内盒的行内级盒被称为原子行内级盒。

图片 2

行盒

在行内格式化上下文中,盒从包含块的顶部一个接一个地水平摆放。包含了一行里所有盒的矩形区域被称为行盒。一个段落就是多个行盒的垂直堆叠。

因此,我们可以得到下图(大致描摹):

图片 3

现在开始计算!

参考文章:
深入了解CSS的line-height属性
Vertical-Align: 你需要知道的所有事【译】
Vertical-Align: All You Need To Know

声明本文转自:

line-height属性的具体定义列表如下:
语法: line-height : normal | <实数> | <长度> | <百分比> | inherit
说明: 设置元素中行的高度。
值: normal:默认行高,一般为1到1.2; 实数:实数值,缩放因子; 长度:合法的长度值,可为负数; 百分比:百分比取值基于元素的字体尺寸。
初始值: normal
继承性: 继承
适用于: 所有元素
媒体: 视觉
计算值: 长度和百分比值为绝对值;其他同指定值。
行高指的是文本行的基线间的距离。而基线(Base line),指的是一行字横排时下沿的基础线,基线并不是汉字的下端沿,而是英文字母x的下 端沿,同时还有文字的顶线(Top line)、中线(Middle line)和底线(Bottom line),用以确定文字行的位置,如图7-17 所示。
图片 4
图7-17 文字的基线
行高与字体尺寸的差称为行距(leading),如图7-18所示。
图片 5
图7-18 行高与行距
7.3.2 内容区域、行内框和行框
理论上讲,一行中的每个元素都有一个内容区域,它是由字体尺寸决定的,如图7-19所示。
图片 6
图7-19 内容区域
行内元素会生成一个行内框(inline box),行内框只是一个概念,它无法显示出来,但是它又确实存在。在没有其他因素影响的时候,行内框等于内容区域,而设定行高则可以增加或者减少行内框的高度,即:将行距的值(行高-字体尺寸)除以2,分别增加到内容区域的上下两边,如图7-20所示。
图片 7
图7-20 行内框与行高
由于行高可以应用在任何元素上,因此同一行内的若干元素可能有不同的行高和行内框高,例如有如下代码,其显示如图7-21所示。
    <p style=”line-height:20px;”>行高20px。<strong style=”line-height:50px;”> 行高50px。</strong><span style=”line-height:30px;”>行高30px。</span></p>
图片 8
图7-21 行内框与行框
这里又有一个新的概念——行框(line box)。同行内框类似,行框是指本行的一个虚拟的矩形框,其高度等于本行内所有元素中行高最大的值。因此,当有多行内容时,每行都会有自己的行框,如图7-22所示。
图片 9
图7-22 多行内容的行框
提示:理解行框和行内框的概念对于学习本章[7.4垂直对齐:vertical-align属性]一节的内容非常重要。
注意:行框的高度只同本行内元素的行高有关,而和父元素的高度(height)无关。
7.3.3 行高的计算与继承
以em、ex和百分比为单位的行高,其基数是元素本身的字体尺寸。例如有代码如下:
    <p style=”font-size:20px;line-height:2em;”>字高20px,行高2em。</p> <p style=”font-size:30px;line-height:2em;”>字高30px,行高2em。</p>
2个段落的行高都为2em,但是字体大小不同,因此显示如图7-23所示。
图片 10
图7-23 行高的计算
行高可以设定得比字体高度小,此时多行的文字将叠加到一起,例如有如下代码,其显示如图7-24所示。
    p { font-size : 20px; line-height :10px; }
    <p>字高20px,行高10px。此时多行的文字将叠加到一起。</p>
图片 11
图7-24 比字体高度小的行高
行高是可继承的,但是继承的是计算值,例如有如下代码:
    p { font-size :20px; line-height : 2em; }
    p span { font-size : 30px; }
    <p>字高20px。<span>字高30px。</span></p>
<p>元素的行高2em,字体尺寸为20px,因此计算值为40px,虽然<span>元素本身的字体尺寸为30px,不过其继承的行高仍为40px。但是在不同的浏览器内显示的效果却不尽相同,如图7-25所示。
图片 12
图7-25 行高的不同表现
由于继承的是计算值,因此当元素内的文字字体尺寸不一样的时候,如果设定固定的行高很可能造成字体的重叠,例如有如下代码,其显示如图7-26所示。
    p { font-size : 20px; line-height : 1em; }
    p span { font-size : 30px; }
    <p>字高20px,行高1em,当文本为多行时可能会发生文字重叠的现象。<span>字高30px。</span></p>
图片 13
图7-26行高继承造成文字叠加
为了避免这种情况,可以为每个元素单独定义行高,但是这样很烦琐,因此可以定义一个没有单位的实数值作为缩放因子来统一控制行高,缩放因子是直接继承的,而不是继承计算值。例如修改上例中的行高为:
    p { line-height : 1; }
则上例中的XHTML代码显示如图7-27所示。
图片 14
图7-27缩放因子对行高的影响
当内容中含有图片的时候,如果图片的高度大于行高,则含有图片行的行框将被撑开到图片的高度,如图7-28所示。
图片 15
图7-28 含有图片的行
注意:图片虽然撑开了行框,但是不会影响行高,因此也不会影响到基于行高来计算的其他属性。
提示:当行内含有图片的时候,图片和文字的垂直对齐方式默认是基线对齐,关于垂直对齐将在本章[7.4 垂直对齐:vertical-align属性]一节中讨论。
7.3.4 浏览器的差别与错误
浏览器在显示的时候往往会有自己的表现形式,例如在Opera内,行高将按照CSS定义的将行距除以2增加到内容区域的上下两边,而IE和Firefox则不是完全平分,如图7-29所示。
图片 16
图7-29 不同浏览器对行高的显示
不过,相差的1至2个像素在实际显示中一般不会有太大的影响,因此可以忽略不计。比较严重的错误是IE 6.0对于含有图片或者表单元等可替换行内元素的行高失效的问题,不过,在IE 7.0中已经修正了这个错误,但是其表现同其它浏览器也不相同。例如有如下代码,其显示如图7-30所示。
    #lineHeight4 p { line-height : 60px; }
    #lineHeight4 fieldset{ border : 0; }
    <div id=”lineHeight4″> <p>内容含有图片在[IE 6]内浏览line-height将失效。<img src=”../../img/ddcat_anim.gif” alt=”图片” width=”88″ height=”31″ /></p> <form id=”testForm” action=”#”> <fieldset> <p><label for=”test1″>表单元素</label>< input type=”text” maxlength=”16″ value=”IE6内行高失效” /></p> </fieldset> </form> </div>
图片 17
图7-30 包含替换元素的行高在IE内失效
由图7-30读者可以发现,IE 7.0中,将半行距分别加在了图片的上下,而由于图片默认是基线对齐,因此文字的基线下移了,这显然不符合CSS中的规定。
对于IE 6.0中行高失效的问题,需要使用CSS Hack手段来针对IE 6.0设定替换元素的上下补白来修正。
提示:关于针对IE 6的CSS Hack,请参见本书[第16章:浏览器与Hack]。
7.3.5 应用:单行文字在垂直方向居中
在网页设计中,往往为了突出标题而添加背景图案,如图7-31所示。
图片 18
图7-31 包含背景图片的标题
假设此标题的XHTML代码如下:
    <div id=”#sample”> <h2>热门帖大盘点</h2> …… </div>
此时如果只设定<h2>的背景图片和高,则文字会偏上,如图7-32所示。
图片 19
图7-32 未设定行高的标题文字
针对这个现象,一般只需要设定与高度相等的行高即可,相关代码如下:
    #sample h2 { height : 31px; line-height : 31px; …… }
此时在浏览器内文字已经在垂直位置上居中显示,如图7-33所示。
图片 20
图7-33 设定行高后的标题文字
此方法同样可以运用在其他需要文字垂直居中显示的地方,例如列表项、导航条等等。
上一小节讲解了行高与单行纯文字的垂直居中,而如果行内含有图片和文字,在浏览器内浏览时,读者可以发现文字和图片在垂直方向并不是沿中线居中,而是沿基线对齐,如图7-34所示。
图片 21
图7-34 文字和图片内容默认垂直对齐方式为基线对齐
这是因为,元素默认的垂直对齐方式为基线对齐(vertical-align: baseline)。

1 行内可替换元素和文档流内行内块可替换元素高度计算

W3C 有明确规范,如下:

如果  height 和  width  计算值均为 auto 且该元素有固有高度,那么该固有高度为 height 使用值。

否则,如果  height 计算值为  auto ,且该元素有一个固有比例,则  height 的使用值为:

width 使用值 / 固有比例

否则,如果  height 计算值为  auto ,且该元素有固有高度,那么该固有高度为  height 使用值。

否则,如果  height 计算值为  auto ,但以上情况均不符合,那么  height  的使用值必须设定为一个最大矩形的高度,该矩形比例为2:1,高度不超过150px,且宽度不大于设备宽度。

因此,在我们的实例中,IMG 盒的高度为 80 10 = 90px。

1、什么是行间距或者行高(line-height)

line-height是指文本行基线间的垂直距离。

2 行内盒的高度计算

“高度”一词在这里颇有歧义,笔者认为,总共可以有三种概念需要辨析:

  • 行内盒的内容区域高度
  • 行内盒的盒高度
  • 计算行盒高度时的行内盒的盒高度

您可能对第二和第三解释抱有疑问,但我们先搁置怀疑,把清楚明白的东西先解决。

当我们用 JavaScript 去获取一个行内盒的 offsetHeight 值时,如我们上面所做的:

JavaScript

document.getElementsByTagName('span')[0].offsetHeight

1
document.getElementsByTagName('span')[0].offsetHeight

笔者将此高度称作“行内盒的盒高度”,类比于我们所熟知的块盒盒高度。其计算值是:

内容区域高度 上下边框 上下内边距 = 行内盒的盒高度

边框和内边距的宽度默认为 0,否则为我们自己指定,但“内容区域高度”是怎么计算的呢?

W3C 这么说:

height 不适用。内容区域的高度应基于字体,但本规范没有指定如何。用户代理可能,比如说,使用行高盒 EM-Box 或字体的最大上端部 Ascender 和下端部 Descender。(后一种会确保有部分在行高盒之上或之下的字符仍然落在内容区域内,但会导致不同字体有大小不一的盒子;前者则确保作者可以控制相对于 line-height 的背景设计,但也导致字符绘制在其内容区域之外。)

言下之意:

  1. height 属性无效
  2. 行内盒内容区域高度在规范里面没有定义,浏览器可以自己折腾

既然规范没有明确规定计算,我们让浏览器实测一下。笔者浏览器测试如下:

  • Chrome 42
  • IE11 42
  • Firefox 43

如果我们更改字体,假设应用如下 CSS

CSS

body { font-family: Simsun; }

1
body { font-family: Simsun; }
  • Chrome 33
  • IE11 37
  • Firefox 35

而如果我们修改 line-height ,以上结果均不受影响。

笔者也曾疑惑,这个 offsetHeight 就是内容区域高度吗?答案:是。笔者的验证方法是基于 W3C 如下规定:

尽管不可替换元素的外边距、边框以及内边距不纳入行盒的计算,它们仍然渲染在行内盒的周围。这意味着如果  line-height  指定的高度小于被包含盒的内容高度,内边距和边框的背景和颜色可能“流进”毗邻的行盒。用户代理应当按文档顺序渲染这些盒。这会造成后面的盒的边框绘制在前面盒的边框和文本上。

您可以用以下代码实测,会发现红色行内盒的背景溢出到了黑色行内盒所在的行盒。

<div> <span style="background:red">Some Text</span> <br/> <span style="background:rgba(0,0,0,.5)">Some Text</span> </div>

1
2
3
4
5
<div>
    <span style="background:red">Some Text</span>
    <br/>
    <span style="background:rgba(0,0,0,.5)">Some Text</span>
</div>

可知内容区域高度,即行内盒没有内边距和边框时的  offsetHeight 。

因此总结论是:

行内盒的内容区域高度计算没有统一的标准,不同的字体或者不同的浏览器都可能导致不同的结果,且其高度与  line-height 无关。

由此我们无法确切地获得一个跨浏览器的行内盒的内容区域高度。同样我们也无法确切获得一个跨浏览器的行内盒高度(因为其计算式里面就包括了不定变量内容区域高度)。

但问题来了,不同浏览器都采用不同的行内盒内容区域高度,又如何能统一计算行盒以及块容器的高度呢?这个问题便导致了笔者在上面所提到的“计算行盒高度时的行内盒的盒高度”概念。

我们进入下一个话题,行盒高度计算。

1.1、顶线,中线,基线,底线

图片 22

从上到下分别是顶线,中线,基线,底线。vertical-align的四个属性top,middle,baseline,bottom就是与这四条线有关。

3 行盒高度计算

根据规范,行盒的高度决定如下:

  1. 计算行盒内每个行内级盒的高度。对于可替换元素、行内块元素以及行内表格元素,高度是其外边距盒的高度;对于行内盒,高度是其  line-height 。
  2. 行内级盒根据其  vertical-align  属性垂直对齐。如果它们对齐  top 或  bottom ,它们必须以能最小化行盒高度的方式对齐。如果这些盒足够高,则有多种解决方案并且 CSS2.1 没有规定此行盒的基线的位置。
  3. 行盒高度是最上盒顶部到最下盒底部的距离。

懂了:W3C 尽管允许浏览器有自己的行内盒内容区域计算方式,但统一了一个行盒高度的计算方式:

计算行盒的高度时,针对行内盒,高度直接取  line-height 。行内盒可以有边框、内边距、外边距,然而跟行盒的高度完全没关系!

根据此规定,我们很快可以得出,计算行盒高度时,SPAN 盒的高度取 32px。

接着,由于我们的  vertical-align 是默认的  baseline ,因此,应当把盒的基线同父盒的基线对齐。如果盒没有基线,对齐盒的下外边距边缘与父盒的基线。也就是说,把 SPAN 盒的基线同 DIV 盒的基线对齐,把 IMG 盒的下外边距边缘同 DIV 盒的基线对齐。

下图是字体的基线、上下端线等位置信息

图片 23

图片来源:

笔者作图如下:

图片 24

假设我们设 DIV 盒的基线是 0,则 IMG 盒的下边缘同 DIV 盒基线对齐;上边缘(上外边距边缘顶部)在高于基线 90px 处。而 SPAN 盒由于其基线对齐 DIV 盒基线,故其行盒下边缘略低于基线。

整个行盒的高度即 IMG 盒上边缘到 SPAN 盒下边缘。假设没有 IMG 元素,则高度为 SPAN 盒的  line-height 。

但读者您可能注意到了,29 和 -3 是怎么得来的呢?下面,笔者带您算!

1.2、行高,行距,半行距

  • 行高是指上下文本行基线间的垂直距离。(上图中两条红线间的垂直距离)
  • 行距是指一行底线到下一行顶线的垂直距离。(第一条粉线和第二条绿线间的垂直距离)
  • 半行距就是行距/2。(图中可以看出,半行距=(行高-字体size)/2 )
![](https://upload-images.jianshu.io/upload_images/2125695-0d6db0a0be6aea55.png)

4 行距和行高计算

29 和 -3 两值是在计算行距和行高后得来的。我们先来看规范:

CSS 假设每种字体都由字体特性来指定一个基线之上的特性高度和之下的特性深度。本节中我们用A表示(给定字体给定字号的)高度,用D表示深度。同时定义 AD = A D,即从顶部到底部的距离。(参见下面如何找到TrueType和OpenType字体的A和D)注意该字体的这些特性是就整个而言的,无须对应任何个别字符的上端部和下端部。

用户代理必须在一个不可替换行内盒中依照字符的相应基线对齐各个字符。接着,就每个字符来决定A和D。注意单个元素的字符可能来自于不同字体因此不见得所有的A和D一样。如果行内盒完全不包含字符,则被视为包含了一个具有元素首个可用字体的A和D的支柱(一个零宽度的不可见字符)。

接着对每个字符添加行距L,其中 L = line-height - AD 。行距的一般添加到A之上,另一半添加到D之下,从而赋予字符以及其行距一个基线之上的完整高度 A’ = A L/2,以及完整深度 D’ = D L/2。

注意。L可能为负。

包含了所有字符以及字符两侧半行距的行内盒的高度正是  line-height 。

我们在上述规定中接触到了这些概念:特性高度 A,特性深度 D,顶部到底部距离 AD,完整高度 A’,完整深度 D’,行距 L。

关于特性值,笔者 Google 到一个网站,推荐读者使用:

不得不吐槽下,国内真的很难找到这样专业精致的字体网站(也可能是我的打开方式不对 >_<)。

好,我们可以获得我们实例中 Microsoft YaHei 的字体特性了:Dcsender -536;Height 2703。

  • AD 即内容区域高度,在本例中是 42
  • D 即字体下端(基线之下)高度,为 42*(536/2703) = 8
  • L = 32 – 42 = -10
  • 故,D’ = 8 -10/2 = 3

即知行内盒的下边缘在基线之下 3px。同时行内盒的高度被视为 32px,故亦知其上边缘在基线之上 29px 处。

我们说啦,整个行盒的高度即 IMG 盒上边缘到 SPAN 盒下边缘。所以得行内盒高度为 90 3 = 93px。

1.3、内容区,行内框,行框

图片 25

  • 内容区:顶线和底线包裹的区域(字体的size)
  • 行内框:在没有其他因素影响的时候(padding等),行内框等于内容区。而设定行高时行内框高度不变,半行距分别增加/减少到内容区的上下两边(深蓝色区域)行框(line box)。(字体size不变,修改行高就是修改行距)
  • 行框:行框高度等于本行内所有元素中行内框最大的值(以行高值最大的行内框为基准,其他行内框采用自己的对齐方式向基准对齐,最终计算行框的高度),当有多行内容时,每行都会有自己的行框。

5 建立行内格式化上下文的块盒的 auto 高度

根据 W3C CSS2.1:10.6.3,该高度是从其上内容边缘到其最后一个行盒的下边缘。只考虑文档流内子盒,绝对定位和浮动子盒应被忽略,相对定位子盒不考虑位移,子盒可以是匿名盒。

在本例中,DIV 盒的行内格式化上下文仅有一个行盒,故其高度取该行盒高度,93px。

1 赞 1 收藏 评论

图片 26

1.4、line-height的设置

百分比方式设置

<body>
  121212
  <p>121212</p>
</body>

body{
  font-size:16px;
  line-height:120%;
}
p{
  font-size:32px;
}

line-height的百分比(120%)和body的字体大小(16px),被用来计算(16*120=19.2),这个值会被层叠下去的元素所继承。

图片 27

图片 28

补充

p{
  font-size:32px;
  line-height:60px;
  padding:10px
}

最终盒模型

图片 29

图片 30

盒模型中,内容(不是上文说的内容区,上文的内容区是顶线与底线间的区域)的高度等于line-height的值。为什么会有margin?浏览器默认P的上下margin是1em,设置了P的font-size是32px,所以1em=32px。上下margin就是32px。

长度方式(px)设置

<body>
  121212
  <p>121212</p>
</body>

body{
  font-size:16px;
  line-height:20px;
}
p{
  font-size:32px;
}

图片 31

图片 32

值normal

<body>
  121212
  <p>121212</p>
</body>

body{
  font-size:16px;
  line-height:normal;
}
p{
  font-size:32px;
}

图片 33

body

body的line的line-height是22px,所以normal等于1.375

图片 34

p的line-height:32px*1.375=44px(normal并不是精确的等于1.375)

图片 35

纯数字
就是将normal改为一个想要的准确数字。

1.5、各种BOX

<body>
  <p>这个<em>强调</em> 元素为行内元素</p>
</body>

body{
  font-size:16px;
  line-height:1.5;
}
p{
  font-size:32px;
  padding:10px;
}

图片 36

containing box
p就是一个containing box,包含了其他boxs。

inline box
在段落内,有一系列的inline box,inline box不会让内容成块显示,而是排成一行。“强调”是一种inline box,“这个”,“元素为行内元素”为一种匿名inline box。

line box
多个inline box组成line box,多个line box组成containing box。

Content Area
Content Area是围绕着文字的一种看不见的box,高度取决与font-size

inline box与line-height
font-size:32px,line-height:48px,行间距=48px-32px=16px,半行间距=8px。
半行间距会用在Content Area的顶部和底部。

图片 37

这里inline box的高度就是line-height。inline box包着Content Area

但是,当line-height小于font-size。line box的高度还是line-height,所以line-box的高度小于Content Area的高度,Content Area会溢出line-box。

图片 38

inline box 与line box
line box的高度取决于他内部最高的inline box。

图片 39

图片 40

图片 41

图片 42

2、vertical-align

vertical-align是用来对齐内联级元素的。设置为以下display属性的元素,它们都被认为属于内联级元素。inlineinline-block or **inline-table **(本文中不涉及此种情况):

inline内联元素基本上是包裹文本的标签。

inline-block内联块元素则如它们的名字所示:拥有内联特性的块元素。他们可以有width和height(可能是由自己的内容定义),以及padding、border和margin。

内联级元素彼此紧挨着放在一行中。一旦有更多的元素被放置到当前行中,一个新的行将会在它下面创建。所有这些行有所谓的“行框”,行框中包含所有的内容。不同大小的内容意味着不同高度的行框。在下面的插图中,行框的顶部和底部都是用红线表示的。

图片 43

在行框中,元素的vertical-align属性是负责垂直对齐的。那么,到底元素垂直对齐的参照物是什么?

参照物:父元素的基线和外边缘
看看元素的基线和行框的外观:
inline元素

图片 44

三行并排的文本。行框的顶部和底部边缘用红线表示,字体的高度由绿线表示,基线由一条蓝线表示。在左边,有一个line-height设置为与字体font-size大小相同高度的文本,绿线和红线重叠在一条线上。在中间,line-height是字体的两倍大。在右边,line-height是字体大小的一半大。

内联元素(display:inline)的外边缘与其行高的顶部和底部边缘对齐,行高可以小于字体的高度。所以,行框就是上面的图中的红线。

内联元素的基线是字符放置的位置线(字母x底部所在的水平线),即图中的蓝线。粗略地说,基线是在字体1/2高度的下面的某个地方。

inline-block元素
inline-block因为已经有宽和高,可能存在多行,每行都有自己的基线和行框,所以会比较特殊。

图片 45

上图中,最外层是div,里面分别是三个inline-block的span,黄色为border,绿色为padding,蓝色为content area(一个span,其中有一个字母“C”)。左边的inline-block的span的内容(span)是一个正常文档流元素。中间的inline-block的span还额外加了overflow: hidden。右边的inline-block的span包含一个流外的span(但内容区域有一个高度)(译者注:流内的元素必须是普通文档流(normal flow)中的元素,流外的元素必须是浮动或绝对定位的元素以及根元素。)。蓝线为每个inline-block的span的基线。内联块元素的外边缘是其margin框的顶部和底部边缘,即图中的红线。

内联块元素(上图三个inline-block的span)的基线取决它包含的内容是否在文档流中:

  • 在流内内容的情况下,内联块元素的基线是正常流中最后一个内容元素的基线(左边的例子)。对于这最后一个元素,它的基线是根据它自己的规则找到的。
<div class="demo1">
  x
    xx
    x

</div>

.demo1 span{
  display:inline-block;
  background-color:silver;
  height:90px;

}

图片 46

灰色背景的元素内部有三个子元素,两个“x”,一个span。元素的基线就是最后一个正常流元素(“x”)的基线。
修改元素的长度,使其内容出现多行:

图片 47

最外面的X怎么也跟着移动了?这涉及行框基线的移动,下文细说。

  • 在流内内容但内联块元素有overflow:hidden属性的情况下,基线是内联块元素margin框的底部边缘(例如在中间的图)。
    修改上面的例子样式:
.demo1>span{
  display:inline-block;
  background-color:silver;
  height:90px;
  width:100px;
  margin:10px;
  overflow:hidden;
}

图片 48

通过最外面的x大致知道行框的基线位置,就是内联块元素的下外边距的地方,也是内联块元素元素的基线位置。
一开始此处有疑惑:内联块元素元素的基线跑到了下外边距处,那么元素里面的内容不应该以这条基线做定位吗?群里问了大佬,内联块元素已经设了宽高,可能有多行(即使只有一行),每行有各自的行框,然后又根据规则定位了,跟内联块元素的基线已经没有关系。

  • 在流外内容的情况下,基线是内联块元素margin框的底部边缘(例如在右边)。
<div class="demo1">
  x
  x

</div>

.demo1>span{
  display:inline-block;
  background-color:silver;
  height:90px;
  width:100px;
}

图片 49

加上浮动

<div class="demo1">
  x
  x

</div>

图片 50

行框的基线是可变的
当使用vertical-align时,基线放置在哪里可能是最令人疑惑的部分。它需要满足vertical-align的值和行框的高度等所有条件。基线的位置犹如是方程中的一个自由参数。

行框的基线是看不见的,但你可以使它很容易看到。只要在文本行的开头添加一个字符,像我增加了一个“X”的字母。如果这个字符不以任何方式对齐,它将默认地坐在基线上。

图片 51

围绕着行框的基线的部分(绿线),我们可以称其为文本框。文本框可以简单地被认为是行框内的内联元素,没有任何对齐。文本框的高度等于它的父元素的字体大小。因此,文本框只围住了行框内的无格式文本。由于这个文本框是绑在基线上的,当基线移动时它将移动。(注:此文本框在W3C规范中称为“strut(支柱)”)

vertical-align的值
1)将元素的基线,参照父元素的基线对齐

图片 52

baseline:元素的基线与父元素的基线对齐。

sub:元素的基线偏移到父元素的基线之下。

sup:元素的基线偏移到父元素的基线之上。

<percentage>:元素的基线相对于父元素的基线偏移了一个百分比(该百分比是对比元素自身的line-height计算得出)。

<length>:元素的基线相对于父元素的基线偏移了一个绝对长度。

2)将元素的中心点,参照父元素的基线对齐

图片 53

middle:将元素的顶部和底部之间的中心点,对齐父元素的基线之上x-height的1/2之处(x-height为字母x的字符高度)。

3)将元素的外边缘,参照父元素的文本框对齐

图片 54

text-top:将元素的顶部边缘,对齐到父元素的文本框的顶部边缘。

text-bottom:将元素的底部边缘,对齐到父元素的文本框的底部边缘。

4)将元素的外边缘,参照父元素行框的外边缘对齐

图片 55

top:元素的顶部边缘对齐到父元素的顶部边缘。

bottom:元素的底部边缘对齐到父元素的底部边缘。

基线的移动
如果一行中有一个高个的元素占据了整行的高度,那么vertical-align对它没有影响。它的顶部和底部没有空间让它移动。为了满足行框基线的对齐方式,行框的基线必须移动。矮个元素设置了vertical-align: baseline。在左边,高个元素设置了vertical-align: text-bottom。在右边,高个元素设置了vertical-align: text-top。你可以看到右边的基线跳起来了。

图片 56

(左)将两个元素放在一行中并设置vertical-align ,它们会使得行框的基线移动到符合它俩的对齐规则之处,然后行框的高度也会随之调整。(中)添加第三个元素,不超越行框的边缘,既不影响行框的高度,也不影响基线的位置。(右)添加第三个元素,如果它超出了行框的边缘,行框的高度和基线调整。在这种情况下,我们的前两个元素也会跟着发生变化。

图片 57

内联级元素底部的小间隙

图片 58

列表项坐在基线上。下面的一点空间,是文本的基线以下预留的depth(在W3C规范中,一个字体的基线以上称为characteristic height,基线以下称为depth)。想要去掉这个depth空隙,有解决的办法吗?只要移动基线的位置就可以,例如通过设置列表项目vertical-align: middle

水平垂直居中

<div class="box">
        <div class="content">
          自适应垂直居中
        </div>
</div>

html{
  height:100%;
}
body{   
   height: 100%;  
   width: 100%;  
}
.box{
   display:inline-block;
   text-align: center;
   width:50%;
   height:50%;
   background-color:#e1e3cd;
   overflow:hidden;
}
.box:after{
    content:"";
    display:inline-block;
    height:100%;
    vertical-align:middle;
}
.content{
    vertical-align:middle;
    background-color:silver;
    display: inline-block;
    width: 50%;
    height:50%;
}

图片 59

要将content水平垂直居中定位在box里,利用vertical-align是其中一种方法。原理是:vertical-align:middle(将元素的顶部和底部之间的中心点,对齐父元素的基线之上x-height的1/2之处(x-height为字母x的字符高度)。),content肯定是要垂直居中的,那只能修改行框的基线位置(注意:不是修改box的基线,box具有宽高,它里面的内容可能会有多行,每行有各自的行框,box的基线已经不会影响内容的布局,但是box的基线还是会受里面内容的影响(内联块元素的基线是正常流中最后一个内容元素的基线)),使其位于box的垂直中心位置。修改行框的基线,只要在box内加一个高度为100%的空元素,然后设置vertical-align:middle,添加的元素已经占满整个行框高度,而只要移动行框的基线,就可以满足定位规则,所以行框的基线就被移动到box垂直中心位置。content再按规则对齐到行框基线上就可以了。

本文由星彩网app下载发布于前端技术,转载请注明出处:行内格式化上下文中的各种高度计算

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。