Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IFC #113

Open
lovelmh13 opened this issue Jul 23, 2021 · 1 comment
Open

IFC #113

lovelmh13 opened this issue Jul 23, 2021 · 1 comment

Comments

@lovelmh13
Copy link
Owner

lovelmh13 commented Jul 23, 2021

visual formatting model 视觉格式化模型

CSS 视觉格式化模型(visual formatting model)是用来处理和在视觉媒体上显示文档时使用的计算规则。该模型是 CSS 的基础概念之一。

视觉格式化模型会根据CSS盒子模型将文档中的元素转换为一个个盒子,每个盒子的布局由以下因素决定:

  • 盒子的尺寸:精确指定、由约束条件指定或没有指定
  • 盒子的类型:行内盒子(inline)、行内级盒子(inline-level)、原子行内级盒子(atomic inline-level)、块盒子(block)
  • 定位方案(positioning scheme):普通流定位、浮动定位或绝对定位
  • 文档树中的其它元素:即当前盒子的子元素或兄弟元素
  • 视口尺寸与位置
  • 所包含的图片的尺寸
  • 其他的某些外部因素

在 IFC 中可能会涉及到的模型有:

  • 行内级元素:inline-level element,display 为 inline、inline-block、inline-table 的元素称为行内级元素。与块级元素一样,元素是否是行内级元素仅是元素本身的属性,并不直接用于格式化上下文的创建或布局。
  • 行内级盒子:inline-level box,由行内级元素生成。行内级盒子包括行内盒子和原子行内级盒子两种,区别在于该盒子是否参与行内格式化上下文的创建。
  • 行内盒子:inline box,参与行内格式化上下文创建的行内级盒子称为行内盒子。与块盒子类似,行内盒子也分为具名行内盒子和匿名行内盒子(anonymous inline box)两种。
  • 原子行内级盒子:atomic inline-level box,不参与行内格式化上下文创建的行内级盒子。原子行内级盒子一开始叫做原子行内盒子(atomic inline box),后被修正。原子行内级盒子的内容不会拆分成多行显示。

观察到,“原子行内级盒子的内容不会拆分成多行显示”,这说明 inline-block 和 inline-table 创建的正是原子行内级盒子。

原因如下:

<style>
.s1 {
  display: inline; /* default value*/
  border: 5px solid rebeccapurple;
}
.s2 {
  border: 5px solid goldenrod;
  display: inline-block;
}
</style>
 
<div style="width: 15em">
  The text in the span
  <span class="s1">can be split in several lines as it</span>
  is an inline box.
</div>
 
<!-- 在同一个行内格式化上下文中,原子行内级盒子( atomic inline-level box ) 不能拆分成多行 -->
<!-- 指定为 inline-block, “cannot be split into several lines as it” 都是在同一个行内,即使因为宽度导致换行,也可以看出,他们还是在同一个区域,并没有被“多行” -->
<div style="width: 15em">
  The text in the span
  <span class="s2">cannot be split in several lines as it</span>
  is an inline-block box.
</div>

image

争议:

css 2 9.2.2 中说:

Inline-level elements generate inline-level boxes, which are boxes that participate in an inline formatting context.

内行级元素 生成参数 IFC 的行内级盒子

这与上面 mdn 中说的 “行内级盒子包括行内盒子和原子行内级盒子两种,区别在于该盒子是否参与行内格式化上下文的创建” 不一致。

IFC - inline formatting context (行内格式化模型)

只要是在某个元素内(即使是块级元素),其内部的内容(文字或者元素)按照书写模式依次排列,就形成了 IFC, 换行会分割成的 IFC。
书写模式:水平方向是从左到右,竖直方向是从上到下排列。

  1. 在一个框里的同一行的区域叫: 行框(line box)。比如下面代码的 .h1 和 .h2 都形成了一个 line box
    行框的的大小足以包含这个行中的所有行内盒子(inline box)。行框的高度是当前所有 行内框 根据 vertical-align 值进行垂直方向对其后,由当前行所有 行内框 最高的顶边和最低底边的实际距决定的。
    如下代码:div 中的 ' One Two Three ' 就是在同一个 IFC 中。
<style>
.h1 {
  writing-mode: horizontal-tb;
}
 
.v1 {
  writing-mode: vertical-rl;
}
</style>
 
<div class="example h1">One Two Three</div>
<div class="example v1">One Two Three</div>

image

  1. 如果一行不够(有宽度设定),将会重新在当前方向上新开一行。
    一个 inline box 被分割成多行时, margin padding border 会在 line box 换行处失效。
    如下代码:
<style>
.s1 {
 border: 5px solid rebeccapurple;
}
</style>
<div class="example" style="width: 20em">
  Before that night—<span class="s1"
    >a memorable night, as it was to prove—hundreds of millions of
    people</span
  >
  had watched the rising smoke-wreaths of their fires without drawing any
  special inspiration from the fact.”
</div>

image

  1. 设定为 inline-block 则不会新开一行
<style>
.s2 {
  border: 5px solid goldenrod;
  display: inline-block;
}
</style>
 
<!-- inline-block -->
<div class="example" style="width: 20em">
  Before that night—<span class="s2">a memorable night, as it was to prove—hundreds of millions of people</span>
  had watched the rising smoke-wreaths of their fires without drawing any special inspiration from the fact.”
</div>

image

  1. 垂直方向的对齐 vertical-align
<style>
.s3 {
  font-size: 200%;
  vertical-align: top;
}
</style>
 
<!-- 垂直方向 -->
<div class="example horizontal">
  Before that night—<span class="s3">a memorable night</span>, as it was to
  prove—hundreds of millions of people had watched the rising smoke-wreaths
  of their fires without drawing any special inspiration from the fact.”
</div>

image

  1. 水平方向的对齐 text-align
<style>
.d4 {
  text-align: center;
}
</style>
 
<div class="example horizontal d4">One Two Three</div>

image

  1. 有浮动的时候

行框(line box) 一般尺寸都相同。但是,在同一个「块级格式化上下文」里,如果有一个浮动元素,浮动元素会让包裹他的 line box 变短。

由于 float 意味着使用块布局,所以它会把 inline inline-block inline-table 等计算为 block,详情见:float mdn

<style>
.d5 {
  background-color: rgb(224, 206, 247);
  border: 5px solid rebeccapurple;
}
.float {
  float: left;
  width: 200px;
  height: 150px;
  background-color: white;
  border: 1px solid black;
  padding: 10px;
}
</style>
 
<div class="d5">
  <div class="float">I am a floated box!</div>
  <p>I am content inside the container.</p>
</div>
</style>

image

white-space 设置如何处理元素中的 空白

image

vertical-align 垂直对齐

先送上一个方便调试的链接:vertical-align 属性测试实验面板

基线

line-height 指定元素行框(line boxes)的最小高度;

vertical-align 的默认值就是基线。

关于 line-height 代码如下,

<style>
.s1 {
  font-size: 40px;
  vertical-align: bottom;
  border: 1px solid red;
  line-height: 100px;
}
</style>
<div class="d1">
  x
  <span class="s1">span</span>
</div>

image

虽然我们是给 span 标签加了 100px 的 line-htight,但是发现 span 高度并不是 100px , 100px 高的是外层的 d1。这充分说明了 line-height 指定的是 line boxe 的最小高度。

从文章前面的描述,我们已经知道了 line-height 是指:在一个框里的同一行的区域。

一、基线位置不固定

image

  1. 在有文字的内联元素中默认基线是字母 x 的下边缘。(汉字的基线不太一样)

“alphabetic” baseline: “字母”基线 – 英文
“hanging” baseline: “悬挂”基线 – 印度文
“ideographic” baseline: “表意”基线 – 中文
image

  1. img 的基线就是图片的底边
  2. inline-block box ( 行内块元素 )
    a. 如果该元素中有内联元素,基线就是最后一行内联元素的基线。
    b. 如果 inline-block box 中没有内联元素或者 overflow 不为 visible,默认基线是 margin-bottom 的顶部。

二、vertical-align 基线对齐

vertical-align 是个相对的对齐的单位。

image
image

前面的 1 2 都不难理解,这里说一下第三点

第三点有两种情况,先看第一种。

  1. 如果该元素中有内联元素,基线就是最后一行内联元素的基线
    上代码:
<style>
  .d1 {
    height: 100px;
    line-height: 100px;
  }
  .s1 {
    display: inline-block;
    border: 1px solid red;
    vertical-align: text-top;
  }
  .s2 {
    font-size: 40px;
    color: darkcyan;
    vertical-align: text-top;
  }
  .img1 {
    display: inline-block;
    vertical-align: text-top;
  }
</style>
 
 
<div class="d1">
  x
  <span class="s1">spanx
    <span class="s2">spanx2是我</span>  
  </span>  
  <img class="img1" src="./1.jpg" alt="" />
</div>

image

这里 spanx2 我懵了,先不说了...

懵逼了看这个:vertical-align 在和谁对齐?

注意一下:

  • top 内联元素的顶边和行内最高元素的顶边对齐(注意,包括 margin,且内联元素有行高,并不是内联元素里的文字与基线对齐,而是元素本身)
<div style="background: #398dee;padding-top:20px">
    <span style="font-size: 30px">x</span>
    <img src="./man_active.png" style="margin-top: 30px">
    <span style="color: red; vertical-align: top;">top</span>
</div>

image

  1. 是和最高元素的顶边而不是和行的顶边对齐。因为设置了行的padding-top之后元素并没有顶在最上面;
  2. 最高元素的顶边包括margin,看图可以发现设置了maigin-top也是会算在内的。图片显示明显“top”的顶部和图片顶不对齐啊,不要忘了top这个元素是有行高的。而这里是说的元素的顶并不是字母的顶部。

是否学会了,测试一下,来看一看,inline-block元素设置margin-bottom为负值后为什么会下移?

image

作者:大漠
链接:https://www.zhihu.com/question/61032688/answer/201637589
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在规范中display取值为inline-block,是这样描述的:

This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.
大致的意思,会让元素生成一个linline-level块容器,而一个inline-block内格式化之后类似于block box,但是元素自身却被格式化一个原子类linline-level box。

反正这样的描述蛮蛋疼的。不过这里说到的inline-block元素,那么他的对齐方式和vertical-align是非常有关系的,默认情况下:

image

是以baseline为基础对齐,这个时候就又引出来baseline的概念了。要了解这个概念和line-height之类的又有关系了。把正复杂,蛋疼。咱先不说。继续说对齐。如果把第二个元素内容去掉:

image

是不是觉得非常的神奇。回到规范中,CSS2的可视化格式模型文档中有一么一段话:

The baseline of an ‘inline-block’ is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its ‘overflow’ property has a computed value other than ‘visible’, in which case the baseline is the bottom margin edge.
大至意思:

‘inline-block’的基线是正常流中最后一个line box的基线, 除非,这个line box里面既没有line boxes或者本身’overflow’属性的计算值而不是’visible’, 这种情况下基线是margin底边缘。

通俗的话描述就是:

一个inline-block元素,如果里面没有inline内联元素,或者overflow不是visible,则该元素的基线就是其margin底边缘,否则,其基线就是元素里面最后一行内联元素的基线。

把你的demo稍为修改一下,先把第二个margin-bottom干掉

image

继续变一下,并在第二个中加方字:

image

这个没有添加任何margin-bottom,第二个成这样了。

会发现,明明尺寸、display水平都是一样的,结果呢,两个却不在一个水平线上对齐,为什么呢?哈哈,上面的规范已经说明了一切。第一个框框里面没有内联元素,因此,基线就是容器的margin下边缘,也就是下边框下面的位置;而第二个框框里面有字符,纯正的内联元素,因此,第二个框框就是这些字符的基线,也就是字母x的下边缘了。于是,我们就看到了框框1下边缘和框框2里面字符x底边对齐的好戏。

其实看到这里,你应该知道一些原因了。把div的文字去掉,然后加上margin-bottom。其实也是改变了元素的baseline了(你就当作改变了)。

如果你在div中添加一个vertical-align改变他的对齐方式。就变了:

image

tips:

ex 单位
1ex 相当于一个 x 字母的高度,不受任何字体的影响。所以是天然对文字居中的。当使用 1ex 的元素的高度小于1ex 时,可以使用这种方法垂直对(不是垂直居中对齐)

未完...

https://www.w3.org/TR/CSS2/visuren.html
https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Visual_formatting_model
https://developer.mozilla.org/zh-CN/docs/Web/CSS/vertical-align
https://www.zhangxinxu.com/wordpress/2015/06/about-letter-x-of-css/
https://www.brunildo.org/test/inline-block.html
https://www.zhihu.com/question/61032688
https://www.jianshu.com/p/ce7e4a997a2c
https://developer.mozilla.org/zh-CN/docs/Web/CSS/Inline_formatting_context
https://developer.mozilla.org/zh-CN/docs/CSS/float
https://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-height
https://www.zhangxinxu.com/wordpress/2010/05/%e6%88%91%e5%af%b9css-vertical-align%e7%9a%84%e4%b8%80%e4%ba%9b%e7%90%86%e8%a7%a3%e4%b8%8e%e8%ae%a4%e8%af%86%ef%bc%88%e4%b8%80%ef%bc%89/
https://drafts.csswg.org/css2/#inline-boxes
https://drafts.csswg.org/css2/#inline-formatting
https://drafts.csswg.org/css2/#value-def-inline-block
https://www.w3.org/TR/CSS2/visuren.html#inline-formatting

@MBearo
Copy link

MBearo commented Jun 20, 2024

偶然间搜到,牛的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants