做者:殷榮檜
參考資料中是我從網上看到的有關塌陷,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官方規範