CSS定位問題(1):盒模型、浮動、BFC

zhiqiang21發表於2016-04-27

引子:

在談到css定位問題的時候先來看一個小問題:

已知寬度(假如:100px)div框,水平居中,左右兩邊分別使用div框填充.且左右div自適應.

效果如下圖: 這裡寫圖片描述

這個問題的難點主要是瀏覽器寬度未知,且兩邊div自適應寬度.

第一種實現方法,是藉助css3的新屬性calc,實現程式碼如下:

第二種實現方式就是藉助與display屬性,將所有的div框具有table的單元格的屬性.

程式碼如下:

這裡解決問題的主要思路是當中間的寬度確定後,因為所有div是單元格所以使用50%使左右的單元格平分剩下的寬度.

1.盒模型

盒模型又分IE盒模型和非IE盒模型: 看下面的一張圖(來自維基百科):

這裡寫圖片描述 由上面的圖可以知道IE和非IE盒模型的區別主要是計算元素的寬度和高度不一樣。

  1. IE瀏覽器: margin-left+width+margin-right
  2. 非IE瀏覽器:margin-left+border-left+padding-left+width+padding-right+border-right+margin-right

看一段程式碼:

效果如下: 這裡寫圖片描述

很明顯我們發現一個問題,就是子元素的margin-top作用在了父元素上。

當我們給父元素新增一個overflow:hidden屬性時,結果正常。

如下圖: 這裡寫圖片描述

這是為什麼呢?

overflow 樣式值為 非 visilbe 時,實際上是建立了 CSS 2.1 規範定義的 Block Formatting Contexts。建立了它的元素,會重新計算其內部元素位置,從而獲得確切高度。這樣父容器也就包含了浮動元素高度。這個名詞過於晦澀,在 CSS 3 草案中被變更為名詞 Root Flow,顧名思義,是建立了一個新的根佈局流,這個佈局流是獨立的,不影響其外部元素的。實際上,這個特性與 早期 IE 的 hasLayout 特性十分相似。

經過測試在IE8以上的瀏覽器表現與chrome和firefox瀏覽器表現效果相同。但是在IE7以下瀏覽器不用設定這個屬性就可以表現正常的效果。如下圖:

這裡寫圖片描述

下面的文字出現錯誤: 很明顯發現的一個問題就是IE8(包括IE8)以上瀏覽器的background-color是border+padding+content.而IE8(不包括)是padding+content。

上面的結論是我在 IE11 瀏覽器中模擬IE8IE9得出的結論,上面的文字是有問題的(可能是因為升級IE11後,瀏覽器的解析核心跟IE8和IE9不一樣,因為微軟IE瀏覽器的標準也是一直在改變的)。

在真實的IE8IE9background-color都僅僅是padding+content 。而IE11中background-colorborder+padding+content; 再來看一個示例,程式碼如下:

我非別在非IE瀏覽器(且>=IE8也同樣的效果)中測試的結果如下:

這裡寫圖片描述

在IE7中的效果如下圖: 這裡寫圖片描述

在<=IE6之下顯示的效果如下(預設會將父級框撐開):

這裡寫圖片描述

關於div的最小(最大)寬度和高度在IE8(>=)之上和非IE瀏覽器上都實現了min-height,maxheight,min-width,max-width這四個屬性。

關於body的問題:

看下面一段程式碼:

並且程式碼的效果圖如下:

這裡寫圖片描述

由上可以知道body是一個特殊的div(盒子)。它的background-color會延伸到margin。

標準流的概念:

在不使用其他的與排列和定位相關的特殊CSS規則時,各種元素的排列規則。


2.浮動

float 屬性定義元素在哪個方向浮動。以往這個屬性總應用於影象,使文字圍繞在影象周圍,不過在 CSS 中,任何元素都可以浮動。浮動元素會生成一個塊級框,而不論它本身是何種元素,且浮動元素的寬度是根據內容的寬度確定的。

看下面的一段程式碼:

然後分別對.test-float1和.test-float2應用樣式,程式碼如下:

效果如下:

這裡寫圖片描述

由上面的程式碼我們可以得出一個結論,span作為一個行內元素本來是沒有width和height屬性的,但是當對行內元素使用float屬性後,該元素具有了width和height屬性

注意:

假如在一行之上只有極少的空間可供浮動元素,那麼這個元素會跳至下一行,這個過程會持續到某一行擁有足夠的空間為止。

浮動的框可以向左或向右移動,直到它的外邊緣碰到包含框或另一個浮動框的邊框為止。由於浮動框不在文件的普通流中,所以文件的普通流中的塊框表現得就像浮動框不存在一樣。

看下面的一段程式碼:

這個時候看到頁面的結果有一個很明顯的bug,如下圖:

這裡寫圖片描述

可以很明顯的看到在浮動的item1和item2有一個間隔沒有在一條水平線上。

這個時候就回到了我們開頭的問題,我們給父級的div盒子新增overflow屬性觸發父級div的BFC。程式碼如下:

效果如下圖:

這裡寫圖片描述

有關BFC的定義:

BFC(W3C CSS 2.1 規範中的一個概念)就是所謂的Block formatting contexts (塊級格式化上下文)。建立了 BFC的元素就是一個獨立的盒子,裡面的子元素不會在佈局上影響外面的元素,反之亦然,同時BFC仍然屬於文件中的普通流。

那麼怎麼觸發BFC呢?

  1. float 除了none以外的值
  2. overflow 除了visible 以外的值(hidden,auto,scroll )
  3. display (table-cell,table-caption,inline-block)
  4. position(absolute,fixed)
  5. fieldset元素

注意:

display:table 本身並不會建立BFC,但是它會產生匿名框(anonymous boxes),而匿名框中的display:table-cell可以建立新的BFC,換句話說,觸發塊級格式化上下文的是匿名框,而不是 display:table。所以通過display:table和display:table-cell建立的BFC效果是不一樣的。


fieldset 元素在www.w3.org裡目前沒有任何有關這個觸發行為的資訊,直到HTML5標準裡才出現。有些瀏覽器bugs(Webkit,Mozilla)提到過這個觸發行為,但是沒有任何官方宣告。實際上,即使fieldset在大多數的瀏覽器上都能建立新的塊級格式化上下文,開發者也不應該把這當做是理所當然的。CSS 2.1沒有定義哪種屬性適用於表單控制元件,也沒有定義如何使用CSS來給它們新增樣式。使用者代理可能會給這些屬性應用CSS屬性,建議開發者們把這種支援當做實驗性質的,更高版本的CSS可能會進一步規範這個。

BFC的特性:

1)塊級格式化上下文會阻止外邊距疊加 當兩個相鄰的塊框在同一個塊級格式化上下文中時,它們之間垂直方向的外邊距會發生疊加。換句話說,如果這兩個相鄰的塊框不屬於同一個塊級格式化上下文,那麼它們的外邊距就不會疊加。 2)塊級格式化上下文不會重疊浮動元素 根據規定,一個塊級格式化上下文的邊框不能和它裡面的元素的外邊距重疊。這就意味著瀏覽器將會給塊級格式化上下文建立隱式的外邊距來阻止它和浮動元 素的外邊距疊加。由於這個原因,當給一個挨著浮動的塊級格式化上下文新增負的外邊距時將會不起作用(Webkit和IE6在這點上有一個問題——可以看這 個測試用例)。 3)塊級格式化上下文通常可以包含浮動 觸發了BFC的話,就不會被float元素覆蓋,當子元素全部浮動的時候也能夠正確地包含了

深入研究浮動:

來看下面的一段程式碼:

顯示效果如下圖:

這裡寫圖片描述

2.1為Box-1設定浮動

效果如下圖:

這裡寫圖片描述

可以看到標準流中的Box-2的文字在圍繞著Box-1排列,而此時的Box-1的寬度不再伸展,而是能容納下內容的最小寬度。 因為此時的Box-1已經脫離了標準流,標準流中的Box-2會頂到原來Box-1的位置(也就是Box-2的左邊框和Box-1的左邊框重合)此時Box-2的文字會圍繞著Box-1排列。

2.2為Box-2設定浮動

效果如下圖:

這裡寫圖片描述

這是很容易看出Box-3和Box-1的左邊框重合。Box-3的文字圍繞Box-2,並且Box-1和Box-2之間的空白是兩者之間的margin產生的。

2.3為Box-3設定浮動

效果如下圖:

這裡寫圖片描述

這個時候可以很明顯的看出三個浮動的盒子(都脫離文件流)都被P標籤的盒子所包圍,並且被文字環繞。

2.4設定Box-3浮動的方向

效果如下圖:

這裡寫圖片描述

這個時候當我把瀏覽器視窗的寬度逐漸的縮小到不能容納三個div寬度的時候,會有什麼效果呢?如下圖:

這裡寫圖片描述

注意:

這種效果我只在IE瀏覽器(<=IE8的瀏覽器中出現更怪異的情況)裡面測試的時候可以小到讓Box-3換行。

在mac下得chrome,firefox和safari當視窗縮小到一定的寬度的時候,就無法在縮小寬度。無法出現Box-3被擠到下一行的情況。

如下圖:

這裡寫圖片描述

這時如果我們設定item2右浮動item3左浮動當我縮小瀏覽器視窗的時候,會出現如下的情況(mac下chrome和safari中仍舊是之上的情況,縮小到一定寬度無法再縮小)。

這裡寫圖片描述

由此我們可以得出一個結論:

當浮動的元素在一行無法顯示完全時,元素會按照普通流的順序(Dom排列順序)被擠到下一行。

2.5浮動的邊界

增加Box-1的高度,當縮小瀏覽器的寬度的時候,會出現如下的現象:

這裡寫圖片描述

主要是因為這個時候Box-3的邊緣被Box-1的邊緣卡住的緣故。

如下圖紅色的地方會有三個margin值:

這裡寫圖片描述

2.6取消浮動的影響

使用CSS屬性Clear,它有三個值left,right,both。

如我們取消p元素左右兩側的浮動:

程式碼如下:

效果如下: 這裡寫圖片描述

2.7浮動的影響

當然浮動對父級元素也會帶來影響,比如說偉大的“塌陷”,看程式碼:

效果如下圖:

這裡寫圖片描述

所有子元素的浮動不會將父級元素的高度撐開。

那麼怎麼解決這個問題呢?

一個很古老的辦法就是在所有子元素的末尾新增一個空的div,並且設定它的clear:both。 看程式碼如下:

效果如下:

這裡寫圖片描述

其實我在IE各版本瀏覽器和非IE瀏覽器中測試的效果都是如上面的效果可意很容易的發現父級的div盒子並沒有被完全的撐開。

不過有大神已經研究出了clearfix的寫法,可以達到最合理的效果,主要目的就是觸發父級盒子自身的BFC。

版本一:

> content:”\200B”;這個引數,Unicode字元裡有一個“零寬度空格”,即 U+200B,代替原來的“.”,可以縮減程式碼量。而且不再使用visibility:hidden。 **版本二:**

經過測試在IE的各個版本的瀏覽器中和非IE瀏覽器都能夠正常的得到結果。

這裡寫圖片描述

推薦閱讀:

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

CSS定位問題(1):盒模型、浮動、BFC CSS定位問題(1):盒模型、浮動、BFC

相關文章