You Don't Know CSS(二)

Float positioning scheme

float本來是用於實現文本環繞圖片效果,但是其卻成為了現代柵格布局的基礎。一旦你理解normal flow是如何工作和inline formatting context是如何切割成line box的,float就很好理解了。設置float屬性可以使得元素使用float positioning scheme。

float可以理解為一個脫離normal flow的塊狀元素。其並不影響其他block-level盒子,但是其會影響block-level盒子內的line box。

註:面試中我們經常被問到的一個問題是「請解釋下什麼是脫離文檔流,或者哪些屬性會使得元素脫離文檔流」,這個問題本身存在問題,規範中沒有脫離文檔流這種說法,只有out of normal flow和in-flow兩種說法,而out of normal 簡單的來說就是不使用normal flow positioning scheme,根據上節所說只有三種positioning scheme:normal flow,floats,absolution positioning,那麼out of flow即使指採用float和absolution positioning的元素。

浮動會使得盒子被移動到當前行的左邊或右邊。關於浮動最有趣的特性是盒子的內容可以圍繞在浮動元素周邊(當然也可以通過clear屬性阻止這種特性)。內容會流動在左浮動元素的右邊或右浮動元素的左邊

Floats有如下特性

  • Floats在布局階段是脫離normal flow的,因此其並不影響塊狀元素的垂直位置。(這個特性說明當考慮存在float的布局時,其並不會影響block-level元素的布局,我們可以假想float元素不存在,當考慮block-level元素內容的line box布局時再考慮float元素的存在
  • Floats與包含容器的左邊緣或右邊緣對齊
  • Floats自左向右或自右向左,按照其在文檔中標記出現的順序排列。換句話說,對於右浮動元素,第一個右浮動元素放在包含容器的右邊緣,第二個右浮動元素則貼近第一個右浮動元素
  • Floats可以影響當前元素或者後續元素line box內的inline-level內容布局。更準確的說是,浮動會導致當前和後續的line box縮短空間為float提供空間。
  • 因為Floats不在normal中,其不影響父元素的高度。這就是為什麼我們需要clearfix的原因
  • Floats可以使用clear屬性清除

如下例所示

.float {n float: left;n height: 500px;n}n.para {n margin: 0;n}n<div class="para blue">Text inside a block-level box placed on a line box before the float</div>n<div class="para green">Text before the float. <div class="float red">The float</div> Text after the float.</div>n<div class="para orange">Text inside a block-level box placed on a line box after the float</div>n

渲染結果如下

從上面例子可以看出:

  • 所有的block-level div都是垂直的排列,就像float不存在一樣
  • float影響了當前和後續的line box的布局,但是沒有影響到第一個div內line box的布局

Floats並不會影響不在同一bfc下的盒子內line box布局。這就是說這些元素要麼在float的一側,要麼放在前面float的下面。如下例所示

.float {n float: left;n height: 500px;n}n.para {n margin: 0;n}n.new-context {n margin: 0;n overflow: auto;n}n<div class="para blue">before</div>n<div class="float red">The float</div>n<div class="new-context green">new formatting context<br>foo bar</div>n<div class="para orange">after</div>n

渲染效果如下

我們可以看出

  • new-context建立了新的formatting context
  • float元素並沒有影響new-context內的line box。new-context緊鄰float的邊緣放置
  • float元素仍然影響了後續div的line box。因為它們沒有創建新的bfc。

這裡我們又看到了bfc的一個應用,如同阻止margin 重疊一樣,這裡bfc起作用是因為float對line box的影響只限於同一bfc下。

這種特性十分有用,大多數的刪格框架都利用了floats和overflow進行布局。

Float clearing

CSS規範允許你通過clear屬性來清除浮動,如下例所示

.left, .right {n width: 35%;n height: 40px;n}n.left {n float: left;n}n.right {n float: right;n}n.clear-left {n clear: left;n}n.clear-both {n clear: both;n}n<div class="left blue">A</div>n<div class="left blue">B</div>n<div class="right red">C</div>n<div class="right red">D</div>n<div class="clear-left orange">Clear left only. Clear left only. Clear left only. Clear left only. Clear left only. Clear left only.</div>n<div class="left blue">E</div>n<div class="left blue">F</div>n<div class="right red">G</div>n<div class="right red">H</div>n<div class="clear-both violet">Clear both. Clear both. Clear both. Clear both. Clear both. Clear both. Clear both.</div>n

渲染效果如下

Floats另一特性是其並不計如父元素的高度計算。如果父元素里除了浮動元素外沒有其他元素,那麼父元素的高度就為0,如下例所示:

.left {n float: left;n width: 35%;n height: 40px;n}n<div class="orange">n <div class="left blue">A</div>n <div class="left blue">B</div>n <div class="left red">C</div>n <div class="left red">D</div>n</div>n

渲染效果如下

原因在於「content-based"的高度計算有兩種形式,對於overflow:visible的block-level元素其高度計算並不記入浮動子元素,而對於overflow為其他值的元素或者設置了清除浮動的元素其高度計算記入浮動子元素。關於高度計算更深入的細節在將在盒子模型那一章里講。

The clearfix

clearfix技巧用於清除浮動。其有幾種變種,下面講一下其機理。

clearfix可以實現如下幾種效果

  • 其可以阻止在被清除浮動的父元素里的浮動子元素影響其他元素里的line box
  • 其可以使得被清除浮動的父元素高度計算記入浮動子元素的高度

如下例所示

.left {n float: left;n width: 15%;n height: 40px;n}n<div class="row clearfix blue">n <div class="left blue">A</div>n <div class="left blue">B</div>n</div>n<div class="row clearfix green">n <div class="left green">C</div>n <div class="left green">D</div>n</div>n<div class="row clearfix orange">n <div class="left orange">E</div>n <div class="left orange">F</div>n</div>n

渲染效果如下

我們想實現每個row單獨成一行有以下三種方法

  • 在父元素的末尾處添加一個元素,其帶有屬性clear:both
  • 使用偽元素方法在父元素的末尾添加一個帶有屬性clear:both的元素
  • 使用overflow:hidden或者overflow:auto讓父元素新建bfc。

代碼如下

偽元素法:

.clearfix:after {n content: "";n display: table;n clear: both;n}n.left {n float: left;n width: 15%;n height: 40px;n}n<div class="clearfix blue">n <div class="left blue">A</div>n <div class="left blue">B</div>n</div>n<div class="clearfix green">n <div class="left green">C</div>n <div class="left green">D</div>n</div>n<div class="clearfix orange">n <div class="left orange">E</div>n <div class="left orange">F</div>n</div>n

新建bfc法:

.clearfix {n overflow: auto;n}n.left {n float: left;n width: 15%;n height: 40px;n}n<div class="clearfix blue">n <div class="left blue">A</div>n <div class="left blue">B</div>n</div>n<div class="clearfix green">n <div class="left green">C</div>n <div class="left green">D</div>n</div>n<div class="clearfix orange">n <div class="left orange">E</div>n <div class="left orange">F</div>n</div>n

其中偽元素方法更為常用,因為其避免了元素溢出帶來的問題。為一個元素設置overflow不為visible的屬性可能使得內容被剪裁,如下所示:

.clearfix-overflow {n overflow: auto;n}n.clearfix-pseudo:after {n content: "";n display: table;n clear: both;n}n.left {n float: left;n width: 15%;n height: 40px;n}n.offset-1 {n position: relative;n top: 15px;n}n.offset-2 {n position: relative;n top: 30px;n}n<div class="clearfix-overflow blue">n <div class="left blue">A</div>n <div class="left offset-1 blue">B</div>n <div class="left offset-2 blue">C</div>n</div>n<br>n<div class="clearfix-pseudo green">n <div class="left green">D</div>n <div class="left offset-1 green">E</div>n <div class="left offset-2 green">F</div>n</div>n

渲染效果如下

我們可以看出使用overflow:auto造成了子元素溢出的部分受到剪裁,這可能不是我們想要的。

而使用clear:both則不會造成這種後果。


推薦閱讀:

CSS 設計理念
移動端實現內滾動的4種方案
外邊距摺疊-磨人的小妖精
Markdown入門指南
「每日一題」為什麼不建議將 font-size 設置為 12px 以下?

TAG:CSS | CSS布局 | 前端开发 |