DOM元素的普通流
格式化上下文即,格式化元素的前后情况或者规则,或者也叫做参照物标准,坐标体系。
DOM元素最原始的格式化上下文,即普通流,没有加任何定位前,元素在HTML文档中的排布方式。
我们把文档流这样定义:
所有的块级元素(block boxes)和行内元素(inline boxes),从上到下,从左到右,给每个元素分配他们自身原始所需要的空间。
其中和文档流有关的,有两种格式化:块格式化( block formatting ),行内格式化( inline formatting )
每个元素box,都会有格式化上下文(formatting context),可以是 block ,或者是 inline,分别是block formatting context和inline formatting context,
但是元素只能属于其中的唯一一种(包括在元素中的文本,默认都会归类为匿名的块级元素或行内元素)。
那么让我们看看block formatting context和inline formatting context对文素的影响,首先看在block formatting context的规则下:
1.块级元素从上到下垂直排列,并独占一行,仅贴父元素。
注意:块级元素不受浮动元素的影响,所以浮动元素才能盖在块级元素上面。
在inline formatting context的规则下,行内元素在父元素的左上角开始,一个接一个的水平排列,如果没有给行内元素设置宽度,那么行内元素会根据元素内部的文本多少来显示宽度。
给行内元素设置背景颜色,并且设置宽高
效果如下:
可以发现宽高对行内元素无效,行内元素的宽高取决于内容的大小,换句话说行内元素是没有宽度属性的。
我们看下浏览器F12中盒子的比例图:
我们再更多增加span元素看看,在inline formatting context下,有什么效果:
我们发现,span文素超出浏览器的窗口大小了,并且超出的部门被截取不显示了,只有向右拉到增宽浏览器宽度,才会把后续的内容展示出来。
我们把浏览器自带的padding和margin去掉会更明显。
看效果:
从这里可以看出,inline formatting context的规则,行内元素是在一行中排列,并且只在一行,它的活动区域就是一行。
我们这样认为,所有的元素,在浏览器渲染后,都会处在block formatting context规则下,或者inline formatting context规则下,并且 最外层元素的参照物或参考坐标系是浏览器。
而拥有BFC特性,即拥有block formatting context的元素,会在最初是的block formatting context规则下,形成一个独立的block formatting context规则区域。
BFC区域只包含在它子元素内的区域,也就是说,如果旁边有不属于它的子元素占据了一部分空间,那么它就会缩小它的空间。
我们来总结下inline formatting context的规则有:
1.行内元素始终处于一行,如果行内元素在块元素内,就在块元素的其中一行内显示。
2.行内元素的内容总宽度超出块元素的宽度,会超出块元素显示,但是行内元素内容不会超出浏览器宽度(废话,但是我还是想写上 = = !)。
inline formatting context对行内元素的属性影响(也可以说是行内元素的特性):
1.行内元素没有width和height,大小由内容决定。
2.行内元素可以设置背景颜色。
而block formatting context规则有:
1.块级元素至上而下排列,并块级元素始终占据浏览器的整行,哪怕是在块元素的内部块元素,也是暂居浏览器的整行,哪怕它设置了固定的宽高,也就是说当前块元素的整行中不会有第二个元素,只有这个块元素。
2.块元素宽度比父元素宽,会超出显示,并且块元素不会超出浏览器宽度。(浏览器的一行内容不会自动换行,也就说浏览器是一行行来渲染的,你这一行的元素安排的合理,那么就全部渲染,如果放多了,整行就无法容纳了)
block formatting context对块元素的属性影响,即块元素的特性:
1.块元素有width和height属性。
2.可以设置背景颜色
3.块元素的margin, padding, width, height ,border 都属于文档流的一部分。
简而言之概括格式化上下文和元素的关系:元素只有遵守格式化上下文的规则,它的属性才能被渲染出来,把元素比成一个个人,那么格式化上下文就是社会规则,人在社会上遵守社会规则才能活好,才能有所表现。
我们来看一个有趣的现象:
一个小盒子和一个大盒子是兄弟元素,小盒子浮动,大盒子拥有BFC特性,因为小盒子脱离了文档流,因此大盒子占据了原本小盒子的文档流空间。
现在给大盒子设置margin: 100px 0 0 100px;
我们发现,由于大盒子的BFC影响区域只包含大盒子的内嵌套元素,即div的开始标签和结束标签内的元素,小盒子不在其中,因此不会跟着大盒子移动,而大盒子的左边距刚好100px,因此小盒子左浮动刚好在大盒子的左边挨着。
但是小盒子却没有向上,跟大盒子一样看似有maargin-top,但是我没有给小盒子设置上边距啊,这是为什么呢?我们看下小盒子的属性图:
我们发现小盒子是没有边距的,那么这就说明小盒子是被动定下来的,侧面也说明了,小盒子是左浮动,没有上浮动,因此上边是受BFC的规则影响的,另外也说明了,margin-top是属于大盒子的空间区域,因此小盒子没有上浮动,那么小盒子就不能暂用大盒子的空间,就只能往下排列。
DOM元素在添加position:absolute后,属性发生了什么变化
如果文档流最大的特点是,获得第一层格式化上下文(block formatting context或者inline formatting context),并且具有与之相应浏览器分配的空间,拥有这些的元素称之为文档流。
另外文档流的很重要的一个特点是整行占据,哪怕是元素设定了宽度,但原元素仍然不愿分点位置给其他元素。
我们来看看除了文档流之外,元素的另外一种规则(非初始规则,额外能赋予的)——position(定位):
static、relative、absolute、fixed、inherit、sticky。
static:
代表不定位,即元素处于最初的文档流规则中。
relative:
我们先来看看与relative有关的一些例子:
渲染效果如下:
目前有两个高度一样的都处于block formatting context规则下的块级元素,现在我们做点尝试,给黄色盒子增加relative定位,并且top: 50px;
结果我们发现变成一个很奇怪的现象,黄盒子确实下移了,但是红色盒子怎么变窄了,我们来看看红盒子的情况:
我们发现红盒子依然是100px的height,那么我们分析出现这样的渲染现象,原因是:
1.relative不脱离文档流,换句话说,黄盒子仍占据0层级的空间(假设给层级划分数字),换句话说,黄盒子在0层级的空间只有从最上边到往下100px的空间。所以说红盒子分配的空间自然就是紧挨着黄河子往下的100px,他们的空间和最开始的一样,这个没变。
2.relative使黄盒子拥有top,left,right,bottom属性(以最近block formatting context元素区域为规则的属性),普通元素是不具备top,left,right,bottom属性,我们可以给红盒子加top属性看看有没有效果:
.box2 {
background-color: red;
height: 100px;
top: 50px;
}
可以发现红盒子没发生任何移动。
那么黄盒子在top属性生效的情况下,下移50px,由于红盒子文档流空间位置不变,因此黄盒子就会盖住红盒子上方50px空间。
我们再看下黄盒子加上left: 50px;
我们看下黄盒子的属性图,黄盒子在margin之外会多了个position的边距,这个postion边距就是relative的特性。(另外postion边距和margin边距是不一样的,postion边距额外加成,margin边距是每个元素都有,并且margin边距会推开其他元素,即可margin边距是被算作文档流中的,也就是包含元素在0层级的空间中的)。
我们给红盒子增加margin-top: 50px;看看效果:
我们可以看到红盒子漏出来了,原因是增加的margin-top: 50px;让红色子效果部分下移50px,刚好就离开了黄盒子的50px遮挡范围。并且我们可以看到margin-top: 50px;也算作红盒子的0层级分配的空间。也就是说红盒子的文档流空间增加到150px了。
相对定位,它的规则有:
1.保留元素的block formatting context规则(元素暂居整行),给红色增加width: 50px;,也发现红盒子不会掉到上面去,黄盒子依然占据整行。
2.元素拥有position 的属性套餐,top,left,right,bottom,并且拥有position 特性的元素永远比设置了z-index的元素层级要高,会居于上面,例如我们这样改代码:
我们直接给红盒子直接来了个10000的z-index,看效果:
红盒子依然在下面。
3.absolute
设置了absolute的元素:
1.同样具有position的属性集合top,left,right,bottom
2.它和relative的最大区别是它脱离了文档流,不具有0级层面的空间。
我们看一个例子:
我们看到黄盒子设置了absolute定位,所以黄盒子脱离了文档流,那么黄河子在文档流中的第一行空间就失去了,重新分配给红盒子了,红盒子就替代了话黄盒子占据了这个空间,同时显示出来。
我们再给黄盒子加个z-index
效果依然不变
我们给黄盒子加上100px的宽度。
我们发现黄盒子显示出来了,我们这才了解到,原来加了absolute的黄盒子层级是比红盒子高,只不过黄盒子除了脱离了文档流,意味着丧失了整行的特性,那么它没设置宽度,宽度就是0,自然就看不到。
另外absolute的元素postion属性的参照物是除了 static 定位以外的第一个父元素(如果没有父元素就参照body元素)
看下面例子:
我们给两个盒子加了个外层包装盒子,并给包装盒子加上margin,发现,两个盒子都跟随包装盒子移动了(亦或者说重新分配了空间,再包装盒子分配完空间后,在包装盒子内部给两盒子分配内部的空间,我们发觉黄盒子脱离文档流后,其初始位置就是它在HTML标签的排序位置,为了证实这一点,我们再看了例子)
我们给两个盒子调换了下位置,黄盒子后渲染,看效果图:
这证实了我们的猜测,黄盒子脱离文档流后,并不会往上往左移动,而是停留在原本位置(没加absolute之前),等待命令。
我们接着做实验,给包装盒子加个static,发现依然没什么变化。
紧接着给黄盒子加top: 50px;
效果如下:
我们发现黄盒子以浏览器为基准来top: 50px,那么我们把包装盒子的static改为relative。
效果如下:
这时候发现黄盒子以包装盒子为参照物来top: 50px。
我们总结absolute的规则有:
1.同样具有position的属性集合top,left,right,bottom,参照物是除了static外的第一个父元素,或者body。
2.它和relative的最大区别是它脱离了文档流,不具有0级层面的空间,因为不会自动填充行,所以如果不给设置宽度,那么脱离文档流时的宽度会变为0。
4.fixed
我们先看下fixed的例子:
红黄盒子被包在一个包装盒子内,包装盒子设定margin,现在红黄盒子都是在文档流中,先后渲染。
现在给黄盒子加上fixed,效果如下:
我们发现黄盒子不见了,因为黄盒子脱离文档流了,没设置width的情况会瞬间失去宽度,给黄盒子设定宽度width: 100px;
同样,黄盒子因为在fixed的加持下,同样有绝对定位效果,层级比文档流元素高。
我们再给包装盒子加relative,并给黄盒子加top: 100px;
我们发现黄盒子是以浏览器为参照物进行top移动,而不是以有relative的包装盒子为参照物。
总结fixed的规则如下:
1.脱离文档流,失去整行效果。
2.拥有position的属性,始终以浏览器(即body为参照物)
5.sticky
先看例子:
同样两盒子被包装盒子包住,我们给黄盒子加上sticky定位,并加上top: 20px;
我们发现黄盒子没任何变化,还在在原来位置,就像普通的文档流元素。
那我们再试着给包装盒子增加高度到可以滚动。
看效果如下:
我们知道包装盒子有50px的margin-top,然后我们移动滚动条,发现,黄盒子不是在滚动到50px才开始粘住固定不变,而是滚动30px就开始站住了,就好像黄盒子增加了20px的高度,固定在浏览器上,另外这20px是相对浏览器的top:20px,而不是相对父元素的top。
我们在做个实验,给包装盒子高度减少到300px
然后,让body变高到滚动
看效果:
滚动时,前面效果依然和给包装盒子增加高度效果一致,也是基于浏览器20px,但是继续滚动,超出包装盒子的300px时。
我们发现,当滚动的高度超出包装盒子高度,黄色盒子不会继续粘住,也就是黄盒子的粘性是基于其父盒子的高度的,如果黄盒子比父盒子高,那么就会丧失粘性。
我们总结sticky的规则:
1.具有position属性,但是 position属性只有在滚动时才发生生效的,目前看position的参照物仍然时浏览器即body。
2.sticky的元素的positon属性要保持效果,那么要保证滚动时,sticky的元素的高度要比父亲元素的总高度高。