1. 程式人生 > >七種右邊固定,左邊自適應兩欄佈局

七種右邊固定,左邊自適應兩欄佈局

參考文章實現了``右邊固定,左邊自適應``的兩欄佈局的七種方法。最終的效果,可以檢視這裡https://hangforfreedom.github.io/some-cases/demo-4/demo.html。  

與原案例不同的是右邊``div``和左邊``div``在html原始碼中的書寫的先後順序也是不同的。  

所以我將右邊div分為兩個類,一個是書寫在左邊div上面的``top-right``,一個是書寫在左邊div後面的``bottom-right``。程式碼如下:  

<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樣式如下:  

.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``方案

.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``方案  


.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;``,自然也就減少了頂端對齊,空格字元佔空間等問題。  

不過由於應用了浮動,父元素需要清除浮動。  

缺點:
 * 需要知道右側盒子的寬度,兩個盒子的距離,還要設定各個元素的``box-sizing``
 * 父元素需要清楚浮動  

# ``float+margin-right``方案  


.wrapper-float{
    overflow: hidden;   /*清除浮動*/
}


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


.wrapper-float .top-right{
    float: right;
}
上面兩種方案都是利用了CSS的``calc()``函式來計算寬度值。下面兩種方案則是利用了``block``級別的元素盒子的寬度具有<strong>填滿父容器,並隨著父容器的寬度自適應的流動特性</strong>。  
但是``block``級別的元素都是獨佔一行的,所以要想辦法讓兩個``block``排列到一起。  

> 我們知道,``block``級別的元素會認為浮動的元素不存在,但是``inline``級別的元素能識別到浮動的元素。這樣,``block``級別的元素就可以和浮動的元素同處一行了。  

以上是原作者在文章中解釋到的。不過,在我的案例中,我嘗試著改動右側``div``和左側``div``的書寫順序,才實現了右側固定,左側自適應的效果。所以程式碼中的類為``top-right``。  
為了讓右側盒子和左側盒子保持距離,需要為右側盒子留出足夠的距離。這個距離的大小為右側盒子的寬度以及兩個盒子之間的距離之和。然後將改值設定為左側盒子的``margin-right``。  

缺點:
 * 需要清除浮動

 * 需要計算左側盒子的``margin-right``  

# 使用``absolute+margin-right``方案  


另外一種讓兩個``block``排列到一起的方法是對右盒子使用``position: absolute;``的絕對定位。這樣,左側盒子也能無視掉它。  

.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``方案  


上面的方法都需要通過右側盒子的寬度,計算某個值,下面三種方法都是不需要計算的。只需要設定兩個盒子之間的間隔。  

.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``方案  

.wrapper-flex{
    display: flex;
    align-items: flex-start;
}


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


.wrapper-flex .left{
    flex: 1 1 auto;
}
``flex``可以說是最好的方案了,程式碼少,使用簡單。  
<strong>需要注意</strong>的是,``flex``容器的一個預設屬性值:``align-items: stretch;``。這個屬性導致了列等高的效果。  
為了讓兩個盒子高度自動,需要設定:``align-items: flex-start;``。  


# ``grid``方案  


.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``外側之間的距離  
連結:
 * 本文參考文章:右邊固定,左邊自適應 https://segmentfault.com/a/1190000010698609