兩欄布局
左邊固定,右邊自適應的兩欄布局
首先創(chuàng)建基本的HTML布局和最基本的樣式。
左邊固定寬度,高度不固定
<div class="wrapper"id="wrapper">
<div class="left"></div>
</div>
基本的樣式是,兩個盒子相距20px, 左側(cè)盒子寬120px,右側(cè)盒子寬度自適應。基本的CSS樣式如下:
.wrapper{padding:15px20px;border:1pxdashed#ff6c60;}
.left{width:120px;border:5pxsolid#ddd;}
.right{margin-left:20px;border:5pxsolid#ddd;}
1.雙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)來動態(tài)計算右側(cè)盒子的寬度。需要知道右側(cè)盒子距離左邊的距離,以及左側(cè)盒子具體的寬度(content+padding+border),以此計算父容器寬度的100%需要減去的數(shù)值。同時,還需要知道右側(cè)盒子的寬度是否包含border的寬度。
在這里,為了簡單的計算右側(cè)盒子準確的寬度,設置了子元素的box-sizing:border-box;以及父元素的box-sizing: content-box;。
同時,作為兩個inline-block的盒子,必須設置vertical-align來使其頂端對齊。
另外,為了準確地應用計算出來的寬度,需要消除div之間的空格,需要通過設置父容器的font-size: 0;,或者用注釋消除html中的空格等方法。
缺點:
需要知道左側(cè)盒子的寬度,兩個盒子的距離,還要設置各個元素的box-sizing
需要消除空格字符的影響
需要設置vertical-align: top滿足頂端對齊
2.雙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);}
缺點:
需要知道左側(cè)盒子的寬度,兩個盒子的距離,還要設置各個元素的box-sizing。
父元素需要清除浮動。
3.float+margin-left方案
.wrapper-float { overflow: hidden; // 清除浮動}
.wrapper-float .left { float: left;}
.wrapper-float .right { margin-left: 150px;}
上面兩種方案都是利用了CSS的calc()函數(shù)來計算寬度值。下面兩種方案則是利用了block級別的元素盒子的寬度具有填滿父容器,并隨著父容器的寬度自適應的流動特性。
但是block級別的元素都是獨占一行的,所以要想辦法讓兩個block排列到一起。
我們知道,block級別的元素會認為浮動的元素不存在,但是inline級別的元素能識別到浮動的元素。這樣,block級別的元素就可以和浮動的元素同處一行了。
為了讓右側(cè)盒子和左側(cè)盒子保持距離,需要為左側(cè)盒子留出足夠的距離。這個距離的大小為左側(cè)盒子的寬度以及兩個盒子之間的距離之和。然后將該值設置為右側(cè)盒子的margin-left。
缺點:
需要清除浮動
需要計算右側(cè)盒子的margin-left
4.使用absolute+margin-left方法
.wrapper-absolute .left { position: absolute;}
.wrapper-absolute .right { margin-left: 150px;}
缺點:
使用了絕對定位,若是用在某個div中,需要更改父容器的position。
沒有清除浮動的方法,若左側(cè)盒子高于右側(cè)盒子,就會超出父容器的高度。因此只能通過設置父容器的min-height來放置這種情況。
5.使用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;}
這個方案同樣是利用了左側(cè)浮動,但是右側(cè)盒子通過overflow: auto;形成了BFC,因此右側(cè)盒子不會與浮動的元素重疊
這種情況下,只需要為左側(cè)的浮動盒子設置margin-right,就可以實現(xiàn)兩個盒子的距離了。而右側(cè)盒子是block級別的,所以寬度能實現(xiàn)自適應。
缺點:
父元素需要清除浮動
6.flex方案
.wrapper-flex { display: flex; align-items: flex-start;}
.wrapper-flex .left { flex: 0 0 auto;}
.wrapper-flex .right { flex: 1 1 auto;}
flex可以說是最好的方案了,代碼少,使用簡單。有朝一日,大家都改用現(xiàn)代瀏覽器,就可以使用了。
需要注意的是,flex容器的一個默認屬性值:align-items: stretch;。這個屬性導致了列等高的效果。
為了讓兩個盒子高度自動,需要設置:align-items: flex-start;
7.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外側(cè)之間的距離。
極限情況
最后可以再看一下在父容器極限小的情況下,不同方案的表現(xiàn)。主要分成四種情況:
動態(tài)計算寬度的情況
兩種方案: 雙inline-block方案和雙float方案。寬度極限小時,右側(cè)的div寬度會非常小,由于遵循流動布局,所以右側(cè)div會移動到下一行。
動態(tài)計算右側(cè)margin-left的情況
兩種方案: float+margin-left方案和absolute+margin-left方案。寬度極限小時,由于右側(cè)的div忽略了文檔流中左側(cè)div的存在,所以其依舊會存在于這一行,并被隱藏。
float+BFC方案的情況
這種情況下,由于BFC與float的特殊關(guān)系,右側(cè)div在寬度減小到最小后,也會掉落到下一行。
flex和grid的情況
這種情況下,默認兩種布局方式都不會放不下的div移動到下一行。不過 flex布局可以通過 flex-flow: wrap;來設置多余的div移動到下一行。 grid布局暫不支持。