总结一下左边固定,右边自适应的两栏布局的七种方法。其中有老生常谈的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布局暂不支持。
若是感受写的有问题,恳请指出。
本文首发于个人博客