七种实现右侧固定,左侧自适应两栏布局的方法

参考文章实现了右边固定,左边自适应的两栏布局的七种方法。最终的效果,可以查看这里

与原案例不同的是右边div和左边div在html源码中的书写的先后顺序也是不同的。

所以我将右边div分为两个类,一个是书写在左边div上面的top-right,一个是书写在左边div后面的bottom-right。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="wrapper wrapper-inline-block" id="wrapper">
    <div class="top-right">     /*书写在左侧div之上*/
        我是右边div:top-right<br><br>
        基本样式:两个div相距20px,右侧div宽200px<br><br><br><br><br>
    </div>
    <div class="left">
        我是左边div:left<br>
        高度有可能会很小,也可能很大。<br>
        我是自适应。我是自适应。我是自适应。我是自适应。我是自适应。我是自适应。我是自适应。
        <br>
    </div>
    <div class="bottom-right">  /*书写在左侧div之下*/
        我是右边div:bottom-right<br><br>
        基本样式:两个div相距20px,右侧div宽200px<br><br><br><br><br>
    </div>
</div>

基本的样式是:两个盒子相距20px,右盒子宽200px,左盒子自适应。基本的CSS样式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.wrapper{
    padding: 15px 20px;
    border: 1px solid #f60;
}

.left{
    margin-right: 20px;
    border: 5px solid #ddd;
}

.top-right,
.bottom-right{
    width: 200px;
    border: 5px solid #ddd;
}

下面的代码就是基于这套基本代码做覆盖,通过容器添加不同的类来实现效果。

inline-block方案


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.wrapper-inline-block{
    box-sizing: content-box;
    font-size: 0;   /*消除空格的影响*/
}

.wrapper-inline-block .left,
.wrapper-inline-block .bottom-right{
    display: inline-block;
    vertical-align: top;    /*顶端对齐*/
    font-size: 14px;
    box-sizing: border-box;
}

.wrapper-inline-block .left{
    width: calc(100% - 225px);
}

这种方法是通过width: calc(100% - 225px)来动态计算左盒子的宽度。225px指的是左盒子距离右盒子的距离,以及右盒子具体的宽度(content+padding+border),以及计算父容器宽度的100%需要减去的数值。同时,还需要知道左侧盒子的宽度是否包含border的宽度。
在这里,为了简单的计算左侧盒子准确的宽度,设置子元素的box-sizing: border-box;以及父元素的box-sizing: content-box;
同时,作为两个inline-block的盒子,必须设置vertical-align来使其顶端对齐。
另外,为了准确的应用计算出来的宽度,需要消除div之间的空格,需要通过设置父容器的font-size: 0;,或者注销消除html中的空格等方法。
缺点:

  • 需要知道右侧盒子的宽度,两个盒子的距离,还要设置各个元素的box-sizing
  • 需要消除空格字符的影响
  • 需要设置vertical-align: top;满足顶端对齐。

float方案


1
2
3
4
5
6
7
8
9
10
11
12
13
14
.wrapper-double-float{
    overflow: auto;    /*清除浮动*/
    box-sizing: content-box;
}

.wrapper-double-float .left,
.wrapper-double-float .bottom-right{
    float: left;
    box-sizing: border-box;
}

.wrapper-double-float .left{
    width: calc(100% - 225px);
}

本方案和双inline-block方案原理相同,都是通过动态计算宽度来实现自适应。但是,由于浮动的block元素在有空间的情况下会依次紧贴,排列在一行,所以无需设置display: inline-block;,自然也就减少了顶端对齐,空格字符占空间等问题。

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-right方案


1
2
3
4
5
6
7
8
9
10
11
.wrapper-float{
    overflow: hidden;   /*清除浮动*/
}

.wrapper-float .left{
    margin-right: 225px
}

.wrapper-float .top-right{
    float: right;
}

上面两种方案都是利用了CSS的calc()函数来计算宽度值。下面两种方案则是利用了block级别的元素盒子的宽度具有填满父容器,并随着父容器的宽度自适应的流动特性
但是block级别的元素都是独占一行的,所以要想办法让两个block排列到一起。

我们知道,block级别的元素会认为浮动的元素不存在,但是inline级别的元素能识别到浮动的元素。这样,block级别的元素就可以和浮动的元素同处一行了。

以上是原作者在文章中解释到的。不过,在我的案例中,我尝试着改动右侧div和左侧div的书写顺序,才实现了右侧固定,左侧自适应的效果。所以代码中的类为top-right
为了让右侧盒子和左侧盒子保持距离,需要为右侧盒子留出足够的距离。这个距离的大小为右侧盒子的宽度以及两个盒子之间的距离之和。然后将改值设置为左侧盒子的margin-right

缺点:

  • 需要清除浮动
  • 需要计算左侧盒子的margin-right

absolute+margin-right方案


另外一种让两个block排列到一起的方法是对右盒子使用position: absolute;的绝对定位。这样,左侧盒子也能无视掉它。

1
2
3
4
5
6
7
8
9
10
11
12
.wrapper-absolute{
    position: relative;
}

.wrapper-absolute .top-right{
    position: absolute;
    right: 20px;
}

.wrapper-absolute .left{
    margin-right: 225px;
}

当然,右侧盒子使用绝对定位后,不仅要调整它的位置right: 20;,还要对其父元素使用相对定位position: relative。这样保证了和左侧盒子距离的准确性。
缺点:

  • 使用了绝对定位,则需要在父元素中使用相对定位position: relative;
  • 更改书写顺序,右div在上左div在下

float+BFC方案


上面的方法都需要通过右侧盒子的宽度,计算某个值,下面三种方法都是不需要计算的。只需要设置两个盒子之间的间隔。

1
2
3
4
5
6
7
8
9
10
11
12
13
.wrapper-float-bfc{
    overflow: auto;
}

.wrapper-float-bfc .top-right{
    float: right;
    margin-left: 20px;
}

.wrapper-float-bfc .left{
    margin-right: 0;
    overflow: auto;
}

这个方案同样是利用了左侧浮动,但是左侧盒子通过overflow: auto;形成了BFC,因此左侧盒子不会与浮动的元素重叠。
这种情况下,只需要为右侧的浮动盒子设置 margin-left,就可实现两个盒子的距离了。而左侧盒子是block级别的,所以宽度能实现自适应。
缺点:

  • 父元素需要清除浮动

flex方案


1
2
3
4
5
6
7
8
9
10
11
12
.wrapper-flex{
    display: flex;
    align-items: flex-start;
}

.wrapper-flex .bottom-right{
    flex: 0 0 auto;
}

.wrapper-flex .left{
    flex: 1 1 auto;
}

flex可以说是最好的方案了,代码少,使用简单。
需要注意的是,flex容器的一个默认属性值:align-items: stretch;。这个属性导致了列等高的效果。
为了让两个盒子高度自动,需要设置:align-items: flex-start;

grid方案


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.wrapper-grid{
    display: grid;
    grid-template-columns: 2fr 200px;
    align-items: start;
}

.wrapper-grid .left,.wrapper-grid .bottom-right{
    box-sizing: border-box;
}

.wrapper-grid .bottom-right{
    grid-column: 2;
}

.wrapper-grid .left{
    grid-column: 1;
}

注意:

  • grid布局也有列等高的默认效果。需要设置:align-items: start
  • grid布局还有一个值得注意的小地方和flex不同:在使用margin-right的时候,grid布局默认是box-sizing设置的盒宽度之间的位置。而flex则是使用两个div的border或者padding外侧之间的距离

链接:

0%