CSS中的行盒(line-boxes)和行内盒子(line-box)
作者:互联网
CSS
盒模型
说到盒模型我们都知道,盒模型有两种,一个content-box和一个border-box 。
关于盒模型。
盒模型
包含块详情
盒模型内部也就是content-box部分有三种情况:
- content-box内部是也是盒子,像俄罗斯套娃一样;
- content-box内部包含着一行一行的line-boxes(行盒);
- content-box 内部两种盒子都存在,但是内部最终还是line-boxes;
每个 HTML 元素实际上是一堆line-boxes。
line-boxes(行盒/行框)
在行内格式化上下文中,line-box(行内盒子)从包含块的顶部开始一个接一个地水平排列。这些行内盒子之间遵循水平边距、边框和填充。这些行内盒子可以以不同的方式垂直对齐:它们的底部或顶部可以对齐,或者它们内部文本的基线可以对齐。形成一个矩形区域称为行框(line-boxes)。
line-box (行内盒子)
一个line-box内部有三种,
- 直接是文本内容的,这种被称为匿名内联元素;
- 非替换元素(例如 span),
- 替换元素(例如img)
匿名内联元素
任何直接包含在块容器元素内(而不是内联元素内)的文本都必须被视为匿名内联元素。
<p>Some <em>emphasized</em> text</p>
上面的代码中 some 和text 由就属于匿名内联元素。
蓝色部分便是一个line-box,也可说三个line-box并列在一块,每个字符一个,三个line-box的都是一样的,所以合在一起说也是一样的。
行距、上高、下深这些名词则是继承而来的,有的甚至是铅字印刷时代的名词。想要详细了解的可以看下。你未必知道的CSS故事:揭开leading的面纱
这些值以及比例是在设计字体时确定的,下面以“Arial”中的“ArialMT”字体为例,说说这些比例。使用fontforge软件打开“Arial”的字体文件我们可以获取一些信息。
根据上面的信息我们可以画出下图
数据以“Arial”为例,非实际比例。
- 2048标准高度(em-square)。不同字体的标准高度不同,比如256、1000、1024、2048等等都可以;
- 上高为1638,下深为410,这一对可以称为默认的上高和下深,有了上高和下深自然就确定了baseline的位置;
- win上高(1854)和win下深(434) 这一对则是windows系统下的上高和下深;HHead上高和HHead下深则是MacOS的,(我没有mac所以也没有测试)有的字体这两对上高和下深可能是不一致的;会出现同样的字体在不同的系统上,显示的位置不同。
- leading(行距/线距),leading的值是一分为二的放在内容区域(content-area)上下两个地方。
- 有了windows系统下的上高和下深以及行距自然就知道了window下的总高度了2355
- capital Height 大写字母的高度,所有大写字母高度都是一样的1467;
- x-height 小写字母x的高度 1062;
- 字形上高1491和字形下深431则指的是,这套字体中所有的字形达到的最高点和最低点,可以看到有的字形是会突破标准的下深的,不同字体设计不同,有的可能会突破上高,但是一般不会突破系统的上高和下深;因为突破了系统的上高和下深,显示的时候可能会出现重叠的情况;
上述的这些数据均是字体设计的时候就确定的,有了这些比例数据,接下来我们了一计算一些计算真实的line-box高度了。
已知
.main{
font-family: Arial;
font-size:100px;
}
- font-size对应的就是标准高度2048,同时它也是1em的值,也是标准行高;
- windows下的上高、下深和行距加起来(2355)对应的就是window下的line-height;
那么: - window下的行高就是 100 / 2048 * 2355 = 114.990234375 ≈ 115,此时115就是window下的line-height的值; 并不是网上传的font-size的1.2或者1.3 什么的,而是字体设计时定下的比例;只不过大多数字体的比例都在1.2 到1.3 这个范围附近,推荐的比例也在这范围附近;当然我们可以重新设置这个比例,比如 设置
line-height:2
; 那么line-height就等于200px = 100 * 2; - 大写字母的高度为 100 / 2048 * 1467= 71.630859375 ≈ 72;
- x的高度就是 100 / 2048 * 1106 = 51.85546875 ≈ 52,这也是1ex的值,(ex可以用来做居中对齐,真居中对齐!!!(* ̄︶ ̄));
- 线距 100 / 2048 * 67 = 3.271484375 ≈ 3, 一半100 / 2048 * 33.5 = 1.6357421875 ≈ 2;
我们知道大多数屏幕上的每个像素都是一个小灯泡,要么亮者要么不亮,所以像素最终会是个整数,具体如何计算的由浏览器决定,不同浏览器可能不同。
以font-size为100px的“Arial”为例,总leading为3,在chrome 中可以看到,1px被分到了上半部分,2px分配到了下半部分;有兴趣的话可以试验下。
非替换元素
非替换元素以span为例,span 标签是通用行内容器,并没有任何特殊语义;
非替换元素的外边距,边框和内边距不会算入行框的计算,但是它们仍然渲染在行内盒周围。这意味着如果用’line-height’指定的高度小于包含的盒(contained boxes)的内容高度,背景与内边距和外边距的颜色可能会“渗入”进相邻的行框。
例如:
它的各条线的位置和匿名内联框相同,计算方式也是相同的。
替换元素
替换元素的内容实际由该内联元素的属性提供,比如img标签的src属性,img标签会使用src属性指定的图片,替换该元素的位置。
关于替换元素各条线的位置,以img为例:
从这个图可以看出img元素的top和text-top在同一条线上,baseline、bottom和text-bottom在同一条线上,leading对其无效。知道了各条线的位置,自然也可确定高度了。textarea也是如此。
上面只是一种解释,其实img元素的text-top和text-bottom线在哪里,我们并不需要知道,因为它是一个line-box 它的内部没有其他内容的。
text-top和text-bottom 这两条线对于line-box它是内部字体渲染是的依据和我们关系不大;这两条线在line-boxes中的时候的比较有用,是line-box根据vertical-align属性确定位置的时候的依据,而line-boxes的各条线的位置则是依据其属性计算出来的。
img和textare元素的baseline是这个盒子的下外边bottom margin 的边线,
input和select 标签的baseline是其内部的文字的baseline,其余线的位置和img相同。
PS:
当其它元素的display被设置为inline-* 的时候,top和text-top,bottom和text-bottom的位置也会如此。元素的top和bottom这两条线并不是固定的,始终在元素的最高和最低点,line-height 和height都会影响其位置。
inline-block 元素的各条线的位置
Inline-block 元素的外边缘(top和bottom)是其margin-box的顶部和底部边缘。
Inline-block 元素的基线取决于该元素是否具有流入内容:
- 在流入内容的情况下,行内块元素的基线是正常流中最后一个行框的基线。对于最后一个元素,它的基线是根据它自己的规则找到的。
- 如果有流入内容但overflow属性为visible以外的其他值,则基线是外边距框的底部边缘。
- 在没有流入内容的情况下,基线边距框的底部边缘。
line-height
关于line-height 有两种说法,一种是line-height指的是两行文字的baseline之间的距离,另一种说法是一行文字的顶部到底部的距离,两者说法不同但是包含的高度是相同的都等于 行距(leading)+ 上高(ascent)+下深(descent),就CSS而言,或者说就本文而言采用第一种方法更容易理解和计算,就先采用第一种了。但是line-height 并不能理解为两条线之间的距离,个人感觉更应该理解为 line-height = 行距(leading)+ 上高(ascent)+下深(descent),不同的字体和字体大小都会计算出来不同的line-height。
如果以baseline为标准给line-height下个更准确的定义的话就是,在font-size font-family相同的情况下相邻两个行盒(line-boxes)内的两个vertical-align相同的行内盒子(line-box)的baseline 距离;
两个相邻的行盒子font-size或者font-family不同导致各自自的line-height不同的时候,它们的各自内部的两个vertical-align相同的行内盒子(line-box)的baseline之间的距离是,各自的line-height除以2然后加起来,如果从这个角度看那么line-height应该是行内盒子(line-box)的top到bottom之间的距离更合理些。
我想这也是当给inline元素设置margin top/bottom以及padding top/bottom 要么无效要么不影响其垂直布局位置的原因。因为最开始css就是这么设计的,毕竟最开始只有inline和block这两种盒子,line-height就是baseline之间的距离,只是后来出现了inline-block 之类的奇怪的盒子导致前面的理论无法解释后面的盒子的行为。
不管怎么说line-height = 行距(leading)+ 上高(ascent)+下深(descent)这个应该是确定的。
line-boxes
了解完line-box,有了line-box的高度,再说回line-boxes,计算line-boxes的高度。line-box都确定的情况下,line-boxes的高度主要受到各个line-box的vertical-aligin 属性影响。
举个栗子:
以仿宋字体为例:
<div class="main">
<span>Ax</span>
<span class="baseline">A</span>
<span class="top">B</span>
<span class="text-top">C</span>
<span class="middle">D</span>
<span class="text-bottom">E</span>
<span class="bottom">F</span>
</div>
.main {
font-family: FangSong;
font-size: 200px;
background-color: rgb(255, 0, 255);
span {
border: 1px solid #ffff;
margin-right: 3px;
background-color: rgb(0, 255, 0);
}
.text-top {
vertical-align: text-top;
}
.text-bottom {
vertical-align: text-bottom;
}
.middle {
vertical-align: middle;
}
.top {
vertical-align: top;
}
.bottom {
vertical-align: bottom;
}
}
为什么显示成这样,我们分析一下它的组成,标出各个子元素以及父元素的各条线的位置就知道了
父元素的 font-family 和font-size已知的情况下行框的text-top、x-height half、 baseline、text-bottom;这四条线的位置就确定了(或者说确定了它们几个的相对位置),同时也确定了top线的最低位置和bottom线的最高位置,而top和bottom线的具体位置则由其子元素的位置确定之后再确定,所有子元素(除了vertical-align为top和bottom的子元素)中所处位置最高的子元素和所处位置最低的子元素分别确定top和bottom,如果所处最高元素的top比依据父元素计算出来的top线的位置低,则以父元素计算的位置为准,bottom同理;top和bottom确定之后也就可以确定vertical-align为top和bottom的子元素的位置。
top和bottom被称作是相对于行的值,所以要在其行框确定之后才能确定它们的位置,而text-top text-bottom baseline 等等被称为相对于父元素的值,只要父元素确定了,它们便确定了。(个人推测,详见vertical-align)它俩有点特殊,具体如下
-
子元素属性为 vertical-align:top 如果该子元素的总高度超过了其它元素计算出来的line-boxes 高度,此时其它线位置均不变,bottom线的位置下移;
-
子元素属性为 vertical-align:bottom ,如果该子元素的高度超过了其他子元素计算出来的line-boxes的高度,此时top线位置不变,其它线均下移;
-
两者都超过的时候,其它线的位置以高的那个为准,相等时以vertical-align:top的为准;
换个角度来说,line-boxes的top和bottom线始终是line-boxes的顶和底;而vertical-align:top/bottom就是始终保持子元素的top/bottom 和line-boxes的对应线重合;
往大了说对于所有的行内盒子(line-box) 来说,在定位的时候其实我们并不需要知道他们的text-top和text-bottom这两个线的位置;vertical-align 定位的时候依赖的是其父元素也就是行盒(line-boxes)的text-top和text-bottom位置,行盒的text-top和text-bottom线的位置则是由其父元素(真实元素)的font-size、font-family等属性决定的。
各个子元素的位置确定之后,line-boxes的top和bottom就可以确定了,然后这个line-boxes高度也就确定了。
- vertical-align 还有几个值 比如sub、super,sub使元素的基线与父元素的下标基线对齐。super使元素的基线与父元素的上标基线对齐。至于上标基线和下标基线在哪里css并没有规定,由浏览器各自的实现确定的;
- vertical-align 可以使用具体值将baseline相对于原有位置上下移动,从这个角度看上面的那些属性值也可以理解为,一个特殊的数字的别名;
- vertical-align 指定为百分比,使元素的基线对齐到父元素的基线之上的给定百分比,该百分比是line-height属性的百分比。可以是负数。
结语
行盒(line-boxes)就像一个集装箱,把形态各异的行内盒子(line-box)包装起来,形成一个标准块(像一块砖头,怪不得叫搬砖的),一行一行的标准块叠起来,组成盒模型的content部分,从整体上来看所有的html标签最终都是由一个一个的line-box组成的。
参考:
- Deep dive CSS: font metrics, line-height and vertical-align
- 深入理解 CSS:字体度量、line-height 和 vertical-align
- line-height
- vertical-align
- 你未必知道的CSS故事:揭开leading的面纱
- css行高line-height的一些深入理解及应用
- 行高的计算与继承
- Vertical-Align: All You Need To Know (CSS)
- [翻译]关于Vertical-Align你需要知道的事情
- css vertical-align你真的很了解嘛
- https://drafts.csswg.org/css-display-3/#non-replaced
- http://www.ayqy.net/doc/css2-1/visudet.html
标签:box,bottom,top,元素,height,boxes,line 来源: https://blog.csdn.net/qq_15601471/article/details/119903856