最开始学习CSS的时候,我一度认为CSS基础很简单,可是CSS布局是一块难啃的骨头。又到后来,我去亚马逊买了畅销书HTML and CSS, design and build websites,书上内容浅显易懂,可是关于CSS布局,也就只有一章,并且彷佛也没有提到复杂的文档流,我印象中也并不知道'BFC', 'Stacking Contexts'这些名词。css
最近的复习中不断出现'负margin','BFC','Stacking Contexts'等等概念,又在MDN上了解到CSS Visual Formatting Model,我以为有必要系统地梳理一遍思路。html
本文以MDN Visual Formatting Model 这篇文章做为引导,并加入本身的理解和新增的知识点,不会涉及太多的布局真实场景,例如双飞翼布局,圣杯布局,多列等高布局等等,这里只做为基础。web
CSS标准盒子模型是呈现每个独立元素的基础,组合起来构成文档流ide
如下是一个标准的盒子,由4个部分组成布局
标准盒模型咱们设置width
属性的时候,width = content-width
,怪异盒模型width = content-width + padding-width + border-width
。post
当咱们设置背景色或者背景图片时,默认会延伸到border外围,可是Z-Ordering的顺序在border如下,也就是说,若是同时设置了background
和border
属性,border区域仍是显示border,可是其Z-Order
如下是background
。咱们可使用background-clip属性改变这一默认行为,具体再也不叙述。学习
<p>test</p>
<p>test</p>
<a href="">test</a>
<a href="">test</a><br />
<a href="">test</a>
<a href="">test</a>
复制代码
p, a {
width: 100px;
height: 40px;
border: 1px solid red;
margin: 20px;
padding: 30px;
}
复制代码
仔细看上面两幅图,块级和行级元素盒子有如下几点不一样flex
仅仅了解完每一个元素本身造成的盒子模型是不够的,由于自身的盒子在某些时候还会受到容器盒子(Containing Block)的影响,例如ui
width
,height
,margin
,padding
,这里须要注意,除了height
是基于父元素盒子的height
以外,其他三个属性都是基于父元素盒子的width
top
,left
等等,此时是基于父元素盒子border内侧进行定位关于容器盒子,咱们最常认为它就是父元素的content部分,其实否则,有以下三种状况spa
static
或者是relative
,则其Containing Block为父元素的content部分absolute
,则其Containing Block为第一个position不为static
的父元素的content+padding部分,若是都是static
,则为Initial Containing BlockInitial Containing Block
The initial containing block has the dimensions of the viewport, and is also the block that contains the
html
element. Simply put, the absolutely positioned element will be contained outside of thehtml
element, and be positioned relative to the initial viewport.简而言之,就是视窗(Viewport)
fixed
,则其Containing Block为视窗(Viewport)知道标准盒子模型以及容器盒子模型后,须要用必定的规则将这些盒子“组装”起来,如下咱们来看看“组装”方式
一旦盒子模型建立成功,接下来即是将这些盒子按照必定规则组装起来,默认的组装规则就是Normal Flow
使用position: relative
或者默认的position: static
,且没有设定浮动,此时元素就是在Normal Flow中
Normal Flow中,块级元素盒子垂直方向一个挨着一个,行级元素盒子水平方向一个挨着一个,一行不够以后换到下一行
若是使用position: relative
,能够将盒子基于原来的位置,经过设定top
,bottom
,left
,right
进行位移
设置一个元素为浮动以后,这个元素盒子在一行中移动到最左边或者最右边,而且脱离Normal Flow
浮动元素对其后面的元素或者是其父元素都会产生影响,除非其后元素使用clear
属性清除这一影响,我以前写过一篇从圣杯和双飞翼看浮动流的文章,里面详细解释了浮动流的过程。
在Floats中,虽然盒子脱离了文档流,可是其对于以后的元素盒子或者是父元素盒子都会产生影响,除非影响被清除。可是在Absolute Positioning Scheme中,盒子能够说彻底抽离Normal Flow,且再也不对其余元素产生影响
此时元素盒子的位置彻底基于其容器盒子(Containing Block),主要两种状况
position: absolute
,容器盒子为第一个position不为static
的父元素的content+padding部分position: fixed
,容器盒子为视窗(Viewport)前面提到的都是元素应该出如今文档中的位置,可是若是发生堆叠,那么显示顺序(Z-Ordering, or Stacking Ordering)是怎么样的呢?
HTML文档默认显示给咱们的是第0层,这也是z-index
的默认值,为0
正常的堆叠顺序,遵循以下几个规则(顺序由底向上,若是发生重叠,只有最上的元素能被用户看到)
<html>
)的background
和border
,在堆底position: static
),根据在HTML文档出现顺序,后面出现的在堆顶static
),根据在HTML文档出现顺序,后面出现的在堆顶display: flex
,且对flex container下的子元素使用order
属性改变顺序,也会影响到堆叠顺序,order
最高的元素出如今堆顶依据上面的规则,咱们看一个例子
首先来看看z-index
的定义
The z-index CSS property specifies the z-order of a positioned element and its descendants or flex items (children of an element with display: flex). When elements overlap, z-order determines which one covers the other. An element with a larger z-index generally covers an element with a lower one.
也就是说,z-index
只能在flex-item或者positioned-items下设置才有效,不然无效
再看一个例子(在上一个例子基础上使用z-index
)
其实咱们使用z-index
,其实是造成了一个Stacking Context,不一样的Stacking Context下的元素层叠顺序互不影响,它们之间的层叠顺序由上层元素之间的层叠顺序决定
建立Stacking Context有以下几种常见方法
<html>
建立了默认的Stacking Contextposition: fixed
或者absolute
的元素,且z-index
值不为默认值auto
display: flex
container下的子元素,且z-index
值不为默认值auto
opacity
值小于1的元素前面提到过,不一样的Stacking Context下的元素层叠顺序互不影响,它们之间的层叠顺序由上层元素之间的层叠顺序决定
z-index
的initial(默认值)为auto
auto
The box does not establish a new local stacking context. The stack level of the generated box in the current stacking context is the same as its parent's box.
也就是说,若是一个元素没有建立Stacking Context,则其顺序由父级Stacking Context决定,最顶层的Stacking Context为根元素<html>
建立,其z-index值为0
仍是先看一个例子,下面分别是文档结构和结果图
Root
到这里Document Flow和CSS Formatting Model也就结束了,涵盖了基本的布局规则。只有深刻理解这些基础,才能更好地去理解之前的一些布局Trick,好比双飞翼布局,圣杯布局等等,这些布局创建在这些基础上,若是理解了这些内容,本身实现一些布局Trick也不是不可能,虽然如今Flex布局已经能够解决不少问题了