本文为winter发布在极客时间的《重学前端》的学习笔记及一些补充。
大家支持正版喔:time.geekbang.org/column/arti…
导语
现在CSS提供了很多种排版方式,我们有很多选项可以选择自己适合的那一种,然而,正常流却是我们绕不开的一种排版。
如果我们从严苛的CSS标准角度去理解正常流,规定排版的算法,就需要引入上述那些复杂的概念。但是,如果我们单纯地从感性认知的层面去理解正常流,它其实是简单的。
盒模型(Box Model)
在讲解CSS排版前,需要了解下CSS盒模型。
CSS盒模型本质上是一个盒子,封装周围的 HTML 元素,包括外边距(marign
),边框(border
),内边距(padding
),内容(content
)。
CSS盒模型有两种,W3C的标准盒模型和IE 盒模型(怪异盒模型):
- W3C 标准盒模型:属性
width
和height
只包含content
,不包括border
和padding
- IE 盒模型:属性
width
和height
包含border
和padding
,指的是content
+padding
+border
css3新增的box-sizing
属性用于切换盒模型:
- content-box 默认值,表示标准盒模型
- border-box,表示IE盒模型
正常流
正常流的行为
我们可以用一句话来描述正常流的排版行为,那就是:依次排列,排不下了换行。
在正常流的基础上,剩下的功能就是基础的延伸:
- float
float相关规则,使得一些盒占据了正常流需要的空间,我们可以把float理解为“文字环绕”。
- vertical-align
vertical-align相关规则规定了如何在垂直方向对齐盒,设置了盒与文字是如何混合排版的。
- margin
我们可以把margin理解为“一个元素规定了自身周围至少需要的空间”。
正常流的原理
在CSS标准中,规定了如何排布每一个文字或者盒的算法,这个算法依赖一个排版的“当前状态”,CSS把这个当前状态称为“格式化上下文(formatting context,即FC)”。
我们可以认为排版过程是这样的:
而我们需要排版的盒,分为块级盒和行内盒。所以排版规则了块级格式化上下文(Block Formatting Contexts,即BFC)和行内级格式化上下文(Inline Formatting Contexts,即IFC),可以简单描述如下:
- 块级格式化上下文顺次排列元素:
- 行内级格式化上下文顺次排列元素:
当我们要把正常流中的一个盒或者文字排版,需要处理以下场景:
- 当遇到块级盒:排入块级格式化上下文。
- 当遇到行内级盒或者文字:首先尝试排入行内级格式化上下文,如果排不下,那么创建一个行盒,先将行盒排版(行盒是块级,由一行中所有的内联元素所组成,所以到第一种情况),行盒会创建一个行内级格式化上下文。
- 遇到float:把盒的顶部跟当前行内级上下文上边缘对齐,然后根据float的方向把盒的对应边缘对到块级格式化上下文的边缘,之后重排当前行盒。
当然,这仅仅是一个简单的逻辑,实际场景中CSS排版渲染会很复杂。
块级格式化上下文(BFC)
创建方式
常见的BFC创建方式如下(更多的创建方式见这里):
- 根元素(
<html>
),这里就可以理解正常流的逻辑 float
的值不为none
。overflow
的值为auto
,scroll
或hidden
。display
的值为table-cell
,table-caption
,inline-block
中的任何一个。position
的值不为relative
和static
。
布局规则
- BFC内部的块盒与行盒,会在垂直方向,一个接一个地放置(正常流)
- 属于同一个BFC的两个相邻盒的垂直方向上的margin会发生重叠,产生折叠边距
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- BFC的区域不会与
float
元素区域重叠(可由上一条推导出) - 每个元素的左外边距与包含块的左边界接触(从左到右),即使浮动元素也是如此。(说明BFC中子元素不会超出他的包含块)
- 计算BFC的高度时,浮动元素也参与计算
BFC的作用
上面的布局规则描述可能有些地方有点抽象,下面简单描述下BFC规则的作用:
- 避免外边距折叠
<div class="container">
<div class="box1"></div>
<div class="box2"></div>
</div>
.box1 {
height: 20px;
margin: 10px 0;
background-color: green;
}
.box2 {
height: 20px;
margin: 20px 0;
background-color: green;
}
根据第二条规则,这两个box会产生重叠,垂直方向上间距为20px
(垂直距离取两个外边距的最大值)。
那么,根据第三条规则,我们可以将其中一个box放在另一个BFC中,来解决这个问题(当然,解决重叠问题还有其他方案,这里只记录BFC的解决方案)。
<div>
<div class="wrapper">
<div class="box1"></div>
</div>
<div class="box2"></div>
</div>
.wrapper {
overflow: hidden;
}
- 清除浮动
清除浮动,其实就是解决浮动元素的包含块高度塌陷的问题。
根据第五条规则,float
元素会沿其容器的左侧或右侧放置。那么,在正常流中,float
元素从网页的正常流动(文档流)中移除,会沿外部容器的左侧或右侧,从而导致其包含块高度塌陷。
<div class="container">
<div class="box">浮动元素</div>
</div>
.container {
border: 1px solid #000
}
.box {
background-color: rgba(0,255,0,0.6);
float: left;
}
所以,我们需要将浮动元素的包含块设置为BFC(也可以使用clear
来解决)。
.container {
border: 1px solid #000;
overflow: hidden;
}
- 自适应两栏布局
float
元素会盖住下面的盒子,但是下面盒子里的文字反而还会环绕float
元素。
<div class="left"></div>
<p>你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好
你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好
你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好
</p>
.left {
float: left;
width: 100px;
height: 100px;
background-color: blue;
}
p {
background-color: green;
width: 200px;
}
那么,我们根据第四条规则,可以将文字所在的盒设置为BFC,将两者隔开。这也是自适应布局的方案。
p {
...
overflow: hidden;
}
而且,还可以通过设置float
元素的margin-right
或者padding-right
实现间距效果(可以参考这篇文章)。
.left {
...
margin-right: 10px;
}
行内级格式化上下文(IFC)
在一个行内格式化上下文中,盒是一个接一个水平放置的,从包含块的顶部开始。
- 这些盒水平方向的
margin
、border
以及padding
属性会起作用 - 这些盒在垂直方向上的对齐方式可以不一样:可以顶部或底部对齐,或根据其中文字的基线对齐
- 行盒的宽度容纳不下子元素时,子元素会换到下一行显示,并且会产生新的行盒
- IFC中时不可能有块级元素的,当插入块级元素时(如p中插入div)会产生两个匿名块与div分隔开,即产生两个IFC,每个IFC对外表现为块级元素,与div垂直排列
行盒(line box)
包含同一行的盒的矩形区域我们称之为行盒(line box)。
- 行盒的高度由
line-height
决定(有多个行内元素,则取line-height
的最大值)。
行盒的高度能够容纳它包含的所有盒。当盒的高度小于行盒的高度时,盒的垂直对齐方式由vertical-align
属性决定。
这里,我们可以理解为什么存在行内元素的上下间距不生效的问题。
- 行盒的宽度由它的包含盒和
float
情况来决定。
通常,行盒的左边接触到其包含盒的左边,右边接触到其包含盒的右边。但是float元素优先排列,可能让行盒的宽度缩短。
<span class="s1">111111</span>
<span class="s2">222222</span>
<span class="s3">333333</span>
<span class="s4">444444</span>
<p>
<span class="s1" style="float: left">111111</span>
<span class="s2">222222</span>
<span class="s3">333333</span>
<span class="s4">444444</span>
由上面的例子我们可以看出,正常情况下盒之间有间距,但是存在float的情况下,盒会紧贴float元素,从而减少行盒的宽度。
并且,当一行的行内级盒的总宽度小于它们所在的行盒的宽度时,它们在行盒里的水平分布由text-align
决定。
IFC的作用
- 水平居中
当一个块元素要在环境中水平居中时,设置其为inline-block
则会在外层产生IFC,通过text-align
则可以使其水平居中。
- 垂直居中
创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其vertical-align:middle
,其他行内元素则可以在此父元素下垂直居中。
总结
每一个盒的排版布局,依赖一个排版的“当前状态”,CSS称为“格式化上下文(formatting context,即FC)”。
盒分为块级盒和行内盒,所以排版规则了块级格式化上下文(Block Formatting Contexts,即BFC)和行内级格式化上下文(Inline Formatting Contexts,即IFC)。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!