總結一下左邊固定,右邊自適應的兩欄佈局的七種方法。其中有老生常談的float
方法,BFC方法,也有CSS3的flex
佈局與grid
佈局。並不是全部的佈局都會在開發中使用,可是其中也會涉及一些知識點。關於最終的效果,能夠查看這裏css
經常使用的寬度自適應的方法一般是利用了block
水平的元素寬度能隨父容器調節的流動特性。另一種思路是利用CSS中的calc()
方法來動態設定寬度。還有一種思路是,利用CSS中的新型佈局flex layout
與grid layout
。html
首先建立基本的HTML佈局和最基本的樣式。git
<div class="wrapper" id="wrapper"> <div class="left"> 左邊固定寬度,高度不固定 </br> </br></br></br>高度有可能會很小,也可能很大。 </div> <div class="right"> 這裏的內容可能比左側高,也可能比左側低。寬度須要自適應。</br> 基本的樣式是,兩個div相距20px, 左側div寬 120px </div> </div>
基本的樣式是,兩個盒子相距20px
, 左側盒子寬 120px
,右側盒子寬度自適應。基本的CSS樣式以下:github
.wrapper { padding: 15px 20px; border: 1px dashed #ff6c60; } .left { width: 120px; border: 5px solid #ddd; } .right { margin-left: 20px; border: 5px solid #ddd; }
下面的代碼都是基於這套基本代碼作覆蓋,經過給容器添加不一樣的類來實現效果。瀏覽器
inline-block
方案.wrapper-inline-block { box-sizing: content-box; font-size: 0; // 消除空格的影響 } .wrapper-inline-block .left, .wrapper-inline-block .right { display: inline-block; vertical-align: top; // 頂端對齊 font-size: 14px; box-sizing: border-box; } .wrapper-inline-block .right { width: calc(100% - 140px); }
這種方法是經過width: calc(100% - 140px)
來動態計算右側盒子的寬度。須要知道右側盒子距離左邊的距離,以及左側盒子具體的寬度(content+padding+border),以此計算父容器寬度的100%
須要減去的數值。同時,還須要知道右側盒子的寬度是否包含border
的寬度。
在這裏,爲了簡單的計算右側盒子準確的寬度,設置了子元素的box-sizing:border-box;
以及父元素的box-sizing: content-box;
。
同時,做爲兩個inline-block
的盒子,必須設置vertical-align
來使其頂端對齊。
另外,爲了準確地應用計算出來的寬度,須要消除div
之間的空格,須要經過設置父容器的font-size: 0;
,或者用註釋消除html
中的空格等方法。
缺點:app
須要知道左側盒子的寬度,兩個盒子的距離,還要設置各個元素的box-sizing
函數
須要消除空格字符的影響佈局
須要設置vertical-align: top
知足頂端對齊。flex
float
方案.wrapper-double-float { overflow: auto; // 清除浮動 box-sizing: content-box; } .wrapper-double-float .left, .wrapper-double-float .right { float: left; box-sizing: border-box; } .wrapper-double-float .right { width: calc(100% - 140px); }
本方案和雙float
方案原理相同,都是經過動態計算寬度來實現自適應。可是,因爲浮動的block
元素在有空間的狀況下會依次緊貼,排列在一行,因此無需設置display: inline-block;
,天然也就少了頂端對齊,空格字符佔空間等問題。code
A floated box is shifted to the left or right until its outer edge touches the containing block edge or the outer edge of another float.
不過因爲應用了浮動,父元素須要清除浮動。
缺點:
須要知道左側盒子的寬度,兩個盒子的距離,還要設置各個元素的box-sizing
。
父元素須要清除浮動。
float+margin-left
方案.wrapper-float { overflow: hidden; // 清除浮動 } .wrapper-float .left { float: left; } .wrapper-float .right { margin-left: 150px; }
上面兩種方案都是利用了CSS的calc()
函數來計算寬度值。下面兩種方案則是利用了block
級別的元素盒子的寬度具備填滿父容器,並隨着父容器的寬度自適應的流動特性。
可是block
級別的元素都是獨佔一行的,因此要想辦法讓兩個block
排列到一塊兒。
咱們知道,block
級別的元素會認爲浮動的元素不存在,可是inline
級別的元素能識別到浮動的元素。這樣,block
級別的元素就能夠和浮動的元素同處一行了。
爲了讓右側盒子和左側盒子保持距離,須要爲左側盒子留出足夠的距離。這個距離的大小爲左側盒子的寬度以及兩個盒子之間的距離之和。而後將該值設置爲右側盒子的margin-left
。
缺點:
須要清除浮動
須要計算右側盒子的margin-left
absolute+margin-left
方法另一種讓兩個block
排列到一塊兒的方法是對左側盒子使用position: absolute
的絕對定位。這樣,右側盒子也能無視掉它。
.wrapper-absolute .left { position: absolute; } .wrapper-absolute .right { margin-left: 150px; }
缺點:
使用了絕對定位,如果用在某個div中,須要更改父容器的position
。
沒有清除浮動的方法,若左側盒子高於右側盒子,就會超出父容器的高度。所以只能經過設置父容器的min-height
來放置這種狀況。
float+BFC
方法上面的方法都須要經過左側盒子的寬度,計算某個值,下面三種方法都是不須要計算的。只須要設置兩個盒子之間的間隔。
.wrapper-float-bfc { overflow: auto; } .wrapper-float-bfc .left { float: left; margin-right: 20px; } .wrapper-float-bfc .right { margin-left: 0; overflow: auto; }
這個方案一樣是利用了左側浮動,可是右側盒子經過overflow: auto;
造成了BFC,所以右側盒子不會與浮動的元素重疊。
an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself。
這種狀況下,只須要爲左側的浮動盒子設置margin-right
,就能夠實現兩個盒子的距離了。而右側盒子是block
級別的,因此寬度能實現自適應。
缺點:
父元素須要清除浮動
flex
方案.wrapper-flex { display: flex; align-items: flex-start; } .wrapper-flex .left { flex: 0 0 auto; } .wrapper-flex .right { flex: 1 1 auto; }
flex
能夠說是最好的方案了,代碼少,使用簡單。有朝一日,你們都改用現代瀏覽器,就可使用了。
須要注意的是,flex
容器的一個默認屬性值:align-items: stretch;
。這個屬性致使了列等高的效果。
爲了讓兩個盒子高度自動,須要設置: align-items: flex-start;
grid
方案又一個新型的佈局方式。能夠知足需求,但這並非它發揮用處的真正地方。
.wrapper-grid { display: grid; grid-template-columns: 120px 1fr; align-items: start; } .wrapper-grid .left, .wrapper-grid .right { box-sizing: border-box; } .wrapper-grid .left { grid-column: 1; } .wrapper-grid .right { grid-column: 2; }
注意:
grid
佈局也有列等高的默認效果。須要設置: align-items: start;
。
grid
佈局還有一個值得注意的小地方和flex
不一樣:在使用margin-left
的時候,grid
佈局默認是box-sizing
設置的盒寬度之間的位置。而flex
則是使用兩個div的border
或者padding
外側之間的距離。
最後能夠再看一下在父容器極限小的狀況下,不一樣方案的表現。主要分紅四種狀況:
動態計算寬度的狀況
兩種方案: 雙inline-block方案和雙float方案。寬度極限小時,右側的div寬度會很是小,因爲遵循流動佈局,因此右側div會移動到下一行。
動態計算右側margin-left的狀況
兩種方案: float+margin-left方案和absolute+margin-left方案。寬度極限小時,因爲右側的div忽略了文檔流中左側div的存在,因此其依舊會存在於這一行,並被隱藏。
float+BFC
方案的狀況
這種狀況下,因爲BFC與float的特殊關係,右側div在寬度減少到最小後,也會掉落到下一行。
flex
和grid
的狀況
這種狀況下,默認兩種佈局方式都不會放不下的div移動到下一行。不過 flex佈局能夠經過 flex-flow: wrap;來設置多餘的div移動到下一行。 grid佈局暫不支持。
若是感受寫的有問題,懇請指出。
本文首發於個人博客