做者:殷荣桧
参考资料中是我从网上看到的有关塌陷,BFC中写的很好的几篇。讲的也很全面,教你如何用BFC,Containing Block(包含块解决)margin塌陷的问题。可是有一点他们都没有说起,就是为何会有这些东西出现。css
1、问题一:为何会有Margin塌陷,是CSS设计时没有考虑到的Bug,仍是设计者有意为之?为何marign塌陷时,水平方向的不会发生塌陷呢?html
2、问题二:CSS1.0中没有BFC,Containing Block.为何要在CSS2.0中加入这两个特性?前端
3、问题三:CSS1.0中没有BFC,Containing Block,又是如何解决Margin塌陷的问题的?git
4、问题四:.BFC除了解决Margin塌陷,还有别的做用吗?程序员
五、问题五:BFC是如何造成的?github
以上的这些问题,若是不去了解设计者的思路,是不太容易理清这些的!理清这些有什么用呢?目的只有一个:让你更好的记住BFC以及Containing Block的用法。千万不能死记硬背,硬背着overflow:hidden能解决margin塌陷。下次换个环境你依然蒙圈,由于你不懂原理,不知道为何!接下来我把我这些天的学习总结记录下,但愿能对您有所帮助。canvas
1、首先第一个问题:浏览器
1.为何会有Margin塌陷,是CSS设计时没有考虑到的Bug,仍是设计者有意为之?为何marign塌陷时,水平方向的不会发生塌陷呢?bash
规范1.0和2.0中分别是这样说的:前端工程师
CSS1.0
Two or more adjoining vertical margins (i.e., with no border, padding or content between them) are collapsed to use the maximum of the margin values. In most cases, after collapsing the vertical margins the result is visually more pleasing and closer to what the designer expects
CSS2.0
无(由于在css1.0中已经规定)
CSS1.0中的规定写的很明白,咱们是故意这样设计的,由于这样在大多数状况下符合平面设计师的要求。这边不由有多了一个疑问,你(CSS设计者)咋知道设计师喜欢这样呢。再说了,要合并也不要你默认就合并了啊,我本身写明就是了,你为何要画蛇添足呢,好比我要垂直间距20px就写成下面这样:
<div style="background-color:tomato;width:100px;height:100px;margin-bottom:20px;">
hello world
</div>
<div style="background-color:#bbb;width:100px;height:100px;margin-top:0px;">
hello world
</div>
我要垂直间距40px就写成下面这样:
<div style="background-color:tomato;width:100px;height:100px;margin-bottom:20px;">
hello world
</div>
<div style="background-color:#bbb;width:100px;height:100px;margin-top:20px;">
hello world
</div>
你偏要帮我把间距(本来20px+20px=40px)应改为20px,还说这样更符合设计师的要求.好像有点说不过去啊,不少人踩过这样的坑(你规范中说好的margin-top就是距离上边界的距离,margin-bottom就是距离下边界的距离,两个一块儿用的时候谁知道你就不按套路出牌了)。为何CSS的制定者们要制定这样一个坑呢,还找了个符合设计师设计的理由呢?一开始我也蒙了,而后我就去stackoverflow上问Why the css specification...。一个老程序员给了我答案:
There's a historic reason. Mostly about how P(Paragraph) elements were rendered in the days before CSS. CSS needed to replicate the existing behaviour. But the behaviour still makes sense today for the reasons given in the question
原来是为了兼容在发明CSS1.0以前使用的P标签
在CSS以前的P标签(上下都有相同的边距)就是以下图所示:
也就是P标签天生就长这样,也没有什么css来让你改他的默认样式。再来看看如今的P标签(其实就是用css修饰的一个display:block;元素)长什么样
引自W3schools
p {
display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
}
复制代码
P标签只是一个壳,重点是要看里面的CSS样式,看见没有,margin-top:1em;margin-bottom:1em;若是没有margin塌陷,他长这样:
中间的间距就比开始个结束的要大,显然很差看(这就是css规范说的更符合设计师的设计),同时,显然也与老的P标签表现的不一致。那怎么办呢?这时CSS的制定者们想了一个主意,把这种状况做为一种特殊状况,另行规定,因而就诞生了margin collapse的官方规定(多规定的其余几项也是为更好的符合平面设计的视觉效果):
首先是一个大前提:元素之间没有被非空内容、padding、border 或 clear 分隔开。而后有符合下面几种毗邻状况:
top margin of a box and top margin of its first in-flow child
一个元素的 margin-top 和它的第一个子元素的 margin-top
bottom margin of box and top margin of its next in-flow following sibling
普通流中一个元素的 margtin-bottom 和它的紧邻的兄弟元素的的 margin-top
bottom margin of a last in-flow child and bottom margin of its parent if the parent has ‘auto’ computed height
一个元素( height 为 auto )的 margin-bottom 和它的最后一个子元素的margin-bottom
top and bottom margins of a box that does not establish a new block formatting context and that has zero computed ‘min-height’, zero or ‘auto’ computed ‘height’, and no in-flow children
一个没有建立 BFC、没有子元素、height 为0的元素自身的 margin-top 和 margin-bottom
这就是margin collapse的由来,因此到这个时候你应该对margin collapse有的完全的了解了。全部的解决margin collapse无非都是破坏了上述的margin collapse成立条件之一。
关于margin collapse,你也能够参考这篇文章www.w3cplus.com/css/underst…
2、接下来第二个问题:
2.CSS1.0中没有BFC,Containing Block.为何要在CSS2.0中加入这两个特性?
在解决这个问题以前:要了解CSS1.0中并无Position(static,absolute,relative,fixed)这个属性,至关于都是static属性。要知道,以前都是一个大的矩形Box套一个小的Box,每一个box的都很安分,一个套一个,并无absolute,fixed这样不受矩形Box model约束的怪物来扰乱Box的排列。
扰乱了以后带来了一个问题:
以前一个在CSS1.0中一个div,p这样的元素若是有margin-top这样的属性,而且值为30%时.
'margin-top'(css1.0中的定义)
Value: length | percentage | auto
Initial: 0
Applies to: all elements
Inherited: no
Percentage values: refer to width of the closest block-level ancestor (注意这边了)
这个30%根据定义就是相对于closest block-level ancestor,说白了就是相对于包住他的那个Box的宽度。
那在css2.0中的width若是是百分比又是相对于谁呢?CSS2.0上是这样写的:
'margin-top', 'margin-bottom'(CSS2.0中的定义)
Value: | inherit
Initial: 0
Applies to: all elements except elements with table display types other than table-caption, table and inline-table
Inherited: no
Percentages: refer to width of containing block (注意这边了)
能够看出CSS2.0中的width是相对于一个叫作containing block这样的一个东西的。如今是时候去了解他了,在了解他以前,就要了解为何好端端的closest block-level ancestor不要了,改用containing block这个了。那是由于出现了Position:absolute | fixed这两个搅局者。接下来就分析一下,为何搅局这的出现会带来containing block这个副产物。
(1)为何css2.0中要增长position这样的一个属性。
设想如今你是一位前端工程师,用的是CSS1.0这套技术。产品要求你在线上已有的网站页面(好比以下的网页布局页面)添加一个永远定位在屏幕右下方的“返回顶部”的按钮。
没有position:fixed这样的属性给你用。那估计够你头疼的,由于你这些布局必然是在一个大的container 的div中,不管你在哪边加,都必然会对现有的布局形成挤压。 以下图:
不管你放在哪一个div中,都将破坏原有的div结构,更致命的是,他不会定位在浏览器的视窗中,由于无法实现相对于浏览器视窗的定位,因此无法实现悬浮。因此,产品的这个简单的需求在CSS1.0时代变得很是难以实现。相似的不少相对于浏览器视窗的悬浮定位都没法实现。
因此制定CSS2.0时,制定者们就想怎么解决这个问题,因而就想到增长一个position的属性,也就是css1.0中的至关于都默认设置了position:static这样的一个属性,另外再增长position:fixed这样的一个属性。他的定位就是相对于浏览器视窗的。那这个时候若是用left:50%时,这个50%确定时相对于浏览器视窗的。不能仍是CSS1.0中的refer to width of the closest block-level ancestor由于closet block-level ancestor并不必定就是浏览器视窗。因此,就想以个名字来称呼这个浏览器视窗,就叫Containing Block吧。Containing Block就这样诞生了。
相对于浏览器视窗的定位解决了。此时,还有一个问题困扰了CSS1.0时代的工程是好久了,好比,产品提出了这样的一个需求:要求在一个设置了overflow:hidden的div中,也放一个“返回顶部”按钮。以下图所示:
这个怎么解决呢?CSS1.0功能又捉襟见肘了。position:fixed也没法实现,那就再加属性值position:absolute;而且让他不只仅是相对于ancestor box,你能够随便指定他相对于谁定位,好比A元素。(只要设置A的position为非static就能够了)。那此时的这个A又怎么称呼呢?还叫containing block吧!
此时,containing block的概念逐渐清晰,咱们再看一下CSS2.0对于containing boxd的定义:
The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:
1.The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The 'direction' property of the initial containing block is the same as for the root element.
2.For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest block container ancestor box.
3.If the element has 'position: fixed', the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media.
4.If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
1.In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
2.Otherwise, the containing block is formed by the padding edge of the ancestor.
If there is no such ancestor, the containing block is the initial containing block.
怎么样,是否是和咱们推断的同样。这就是Containing Block的诞生记。
知道了有Containing Block的缘由以后,咱们再来看一下,为何又会诞生BFC(Block Format Context)这样的东西。
前面,咱们提到CSS1.0,CSS2.0中都有默认的margin collapse,那我若是咱们就是不想要这个塌陷呢!这个是后CSS的制定者们又想,能不能制定一个属性,让上下的两个div隔离开来,就像孙悟空给唐僧用金箍棒画的圈同样,外界的妖魔鬼怪都没法进入,这样让他们的Margin不会塌陷合并。制定者们给金箍棒画的这个圈取了个名字叫BFC。他们还制定了触发BFC的条件,这要符合这些条件中的一个,就能请来孙悟空画上隔离区。符合触发BFC的条件以下:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
有了BFC就可已很好的解决margin collapse.这里我就不细说了,你能够参考这篇文章:css中的BFC
3.CSS1.0中没有BFC,Containing Block,又是如何解决Margin塌陷的问题的? 这个在第一个问题中说起到了,只要破坏margin collapse成立的任何一个条件就能够了。
4.BFC除了解决Margin塌陷,还有别的做用吗?
就和爱迪生一开始发明灯泡只是为了照明,但后来被人们用到KTV渲染气氛了同样。BFC也同样,发明他的时候是为了隔离,由于隔离诞生了不少做用,仍是参考这样的一篇文章css中的BFC
5.BFC是如何造成的?
1.根元素(整个页面就是一个大的BFC);
2.float为 left | right;
3.overflow为 hidden | auto | scroll;
4.display为 inline-block | table-cell | table-caption | flex | inline-flex;
5.position为 absolute | fixed;
总结:至此你知道了为何在CSS中有Margin collapse,BFC,Containing Block.这些事物,相信这样必定能比你硬记住这记住怎么用会更牢靠。
参考资料:
理解CSS中的BFC(块级可视化上下文)[译] css中的BFC 深刻理解BFC和Margin Collapse CSS 中 block-level boxes、containing block、block formatting context 三者之间的区别和联系是怎样的? CSS1.0官方规范 CSS2.0官方规范