多列布局

多列布局在一個網(wǎng)頁設(shè)計中非常常見,不僅可以用來做外部容器的布局,在一些局部也經(jīng)常出現(xiàn)多列布局,比如下面圈出來的都是多列布局:

image-20200113220846222

定寬 + 自適應(yīng)

定寬 | 自適應(yīng)

我們先講一個最簡單的兩列布局,左邊列定寬,右邊列自適應(yīng):

image-20200113221036196

下面我們來看看有哪些方法可以解決這個問題:

float + margin

我們有如下html代碼:

<div class="parent">
  <div class="left">
    <p>left</p>
  </div>
  <div class="right">
    <p>right</p>
    <p>right</p>
  </div>
</div>

當我們沒有給他設(shè)置樣式的時候,它是這樣子

image-20200113222241883

我們要的是兩列布局,所以我們給left加一個float:left;,然后它變成這樣了:

image-20200113222421242

我們看到right的內(nèi)容環(huán)繞了left,這是浮動(float)的一個特性,那怎么解決呢? 因為右邊環(huán)繞了左邊,我們只需要將右邊往右邊移過去就行了: margin-left: 100px;如果左右兩列還想要一點間距,margin-left設(shè)置大一點就行了。

image-20200113223157002

float + overflow

這個方案和前面的float + margin的方案很像,只是解決右邊環(huán)繞左邊的思路不一樣,我們先給左邊寫float:left;右邊還是會環(huán)繞左邊:

image-20200113222421242

這次我們解決這個問題不用margin-left了,而是用overflow:

image-20200113223619772

這種方案如果要間距,可以在left上設(shè)置一個margin-right: 20px;。為什么overflow:hidden可以決絕浮動環(huán)繞的問題呢,這其實用到了BFC的原理。下面我們來講講BFC:

BFC

BFC(Block Formatting Context)塊級格式上下文,是Web頁面中盒模型布局的CSS渲染模式,指一個獨立的渲染區(qū)域或者說是一個隔離的獨立容器。

下列情況都可以形成一個BFC:

1\. 浮動元素,float 除 none 以外的值; 
2\. 定位元素,position(absolute,fixed); 
3\. display 為以下其中之一的值 inline-block,table-cell,table-caption; 
4\. overflow 除了 visible 以外的值(hidden,auto,scroll);

BFC有如下特性:

1\. 內(nèi)部的Box會在垂直方向上一個接一個的放置。
2\. 垂直方向上的距離由margin決定
3\. bfc的區(qū)域不會與float的元素區(qū)域重疊。
4\. 計算bfc的高度時,浮動元素也參與計算
5\. bfc就是頁面上的一個獨立容器,容器里面的子元素不會影響外面元素。

上面幾個特性怎么理解呢?

  1. 如果垂直方向上有多個div,他們都有margin,那垂直的margin會合并

    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
    </div>
    
    .child {
        margin-top: 10px;
        margin-bottom: 20px;
    }
    
    

    上述代碼兩個child之間的間距是20px,而不是30px,因為垂直的margin會合并。但如果我給上面第一個child再套一個容器,使用overflow:hidden;他就成了一個BFC,根據(jù)BFC的特性,BFC的子元素不會影響外面的元素,margin就不會合并,兩個child的間距就是30px;

    <div class="parent3">
      <div class="overflow">
        <div class="child3">child4</div>
      </div>
      <div class="child3">child4</div>
    </div>
    
    .child3 {
        margin-top: 10px;
        margin-bottom: 20px;
    }
    
    .overflow {
        overflow: hidden;
    }
    
    
  2. BFC是一個獨立的容器,不會被浮動元素覆蓋,里面的文字也不會環(huán)繞浮動元素,我們這里的兩欄布局就是利用的這個特性。

  3. 計算BFC高度時,浮動元素的高度也會計算其中,這不就是我們用來清除浮動的一種做法嗎?

    .parent {
        overflow: hidden;
    }
    
    

table

我們還可以用table來實現(xiàn),父級設(shè)置display為table,那他的寬度就是內(nèi)容的寬度,所以我們需要手動指定寬度為100%。兩個子級設(shè)置display為table-cell,這樣他們其實就相當于table的兩個單元格。由于我們要固定左邊的寬度,父級table應(yīng)該使用布局優(yōu)先,即table-layout: fixed;。這時候如果左右兩邊要間距,是沒法設(shè)置margin的,因為他們是單元格,但是我們可以在左邊子級上設(shè)置padding-right.

<div class="parent4">
  <div class="left4">
    <p>left4</p>
  </div>
  <div class="right4">
    <p>right4</p>
    <p>right4</p>
  </div>
</div>

.parent4 {
    display: table;
    width: 100%;
    table-layout: fixed;
}

.left4 {
    display: table-cell;
    width: 100px;
    padding-right: 20px
}

.right4 {
    display: table-cell;
}

table-layout

table-layout有兩個值:

  • fixed: 是表格布局優(yōu)先,列寬由表格寬度和列寬度設(shè)定,而與單元格的內(nèi)容無關(guān)。這種模式下,瀏覽器在接收表格第一行后就可以渲染出來,速度更快。
  • auto: 這是默認值,表示表格內(nèi)容優(yōu)先,列的寬度是由列單元格中沒有折行的最寬的內(nèi)容設(shè)定的。此算法有時會較慢,這是由于它需要在確定最終的布局之前訪問表格中所有的內(nèi)容。

flex

又遇到flex了,用flex做這種布局太簡單了,直接父級設(shè)置display: flex, 左子級定寬,右子級設(shè)置flex:1就行了,如果要間距,可以直接用margin。

.parent5 {
    display: flex;
}

.left5 {
    width: 100px;
    margin-right: 20px;
}

.right5 {
    flex: 1;
}

flex: 1

flex: 1flex: 1 1 0的簡寫,對應(yīng)的完全體是:

{
    flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
}

  • flex-grow:設(shè)置元素的擴展比例。假如父級元素總寬度為500px, 子元素A, B, C三個元素的flex-grow分別為1, 2, 2,那他們的寬度比例為1:2:2,三個元素最終的寬度為100px, 200px, 200px;
  • flex-shrink: 設(shè)置元素的收縮比例。假如父級元素總寬度為500px,現(xiàn)在有A, B, C, D, E五個子元素,他們的flex-shrink分別為1, 1, 1, 2, 2,他們的flex-basis都是120px。計算可知,五個子元素總寬度為120 *5 = 600px,超出了父級100px,所以需要對子元素進行收縮。收縮的時候就要通過flex-shrink來計算,我們發(fā)現(xiàn)他們flex-shrink的總和為1 + 1 + 1 + 2 + 2 = 7。所以將超出的100px分成7份,每份約14px,然后按照flex-shrink進行收縮。A, B ,C的份數(shù)都是1,所以他們收縮14px,他們的最終寬度是120 - 14 = 106px;D, E的份數(shù)是2,所以他們應(yīng)該收縮14 *2 = 28px,最終寬度是120 - 28 = 92px。
  • flex-basis: 設(shè)置元素的初始值,擴展和收縮都以此為參照物。

定寬 | 定寬 | 自適應(yīng)

三列布局,前面兩列定寬,最后一列自適應(yīng),這個跟前面的一列定寬,一列自適應(yīng)的很像,很多方案都可以直接用, 比如用float + overflow。

image-20200114162854615

不定寬 + 自適應(yīng)

image-20200114163050252

兩列布局,左邊不定寬,寬度由內(nèi)容決定,右邊自適應(yīng)的常見解決方案:

不定寬:float + overflow

跟前面定寬的寫法很像,只是左邊子級寬度不能寫死了,要留給它的子元素決定。

image-20200114163359831

不定寬:table

用table也可以實現(xiàn),但是要注意,table-layout不能設(shè)置fixed了,因為左邊寬度不定,我們可以不設(shè)置他,這樣就是默認值auto。默認的table天生寬度就是內(nèi)容決定的,左右兩邊如果內(nèi)容一樣長,那他們的長度可能是一樣的,都有留白,像這樣:

image-20200114163857549

但是我們想要的是左邊擠到內(nèi)容區(qū),留白都給右邊,只需要給左邊一個很小的寬度,比如width: 0.1%或者1px都行。

image-20200114164209914

不定寬:flex

又是flex,跟之前定寬的很像,只需要把前面左邊的寬度去掉就行了。

.parent5 {
    display: flex;
}

.left5 {
    margin-right: 20px;
}

.right5 {
    flex: 1;
}

多列不定寬 + 自適應(yīng)

image-20200114164529075

多列不定寬+自適應(yīng)前面幾種方案都可以實現(xiàn),以float + overflow為例:

image-20200114164719925

等寬

image-20200114164804503

等寬布局就是幾個元素,每個元素的寬度是一樣的,而且他們之間還可能有間距。如果沒有間距,這個很好實現(xiàn),每個元素寬度25%就行了,但是如果有間距,還設(shè)置25%,里面的內(nèi)容就超出父容器了,就會掉下來。那應(yīng)該怎么做呢?仔細看寫,我們會發(fā)現(xiàn)他們有如下關(guān)系:

image-20200114165200857
C = W * N + G * (N -1);  // 此處N為4
// 變換為
C = W * N + G * N - G;
// 再變?yōu)?C = (W + G) * N - G;
// 最后變?yōu)?C + G = (W + G) * N;

C + G = (W + G) * N;對應(yīng)的示意圖為:

image-20200114165625839

這次我們的html結(jié)構(gòu)如下所示,間距是20px:

<div class="parent6">
  <div class="column"><p>1</p></div>
  <div class="column"><p>2</p></div>
  <div class="column"><p>3</p></div>
  <div class="column"><p>4</p></div>
</div>

等寬:float

通過前面的公式可知,我們需要將父級拓寬一個間距,即20px,用margin-left: 20px即可實現(xiàn)。每個子元素左浮動,寬度為25%,同時padding-left: 20px,這個是間距,我們?yōu)榱俗岄g距是在寬度內(nèi)部減出去,還需要設(shè)置box-sizing: border-box;。

.parent6 {
    margin-left: -20px;
}

.column {
    float: left;
    width: 25%;
    padding-left: 20px;
    box-sizing: border-box;
}

image-20200114171032294

用float的方式布局有一個不足之處,就是我們寫死了25%,這個只適用于4列,如果不知道幾列就不能這么寫了,當然用JS動態(tài)計算不算。

等寬:table

用table就不用寫死25%,因為在table-layout:fixed的情況下,列寬不是根據(jù)內(nèi)容計算的,默認列寬是相等的,天生就是等寬。但是在實現(xiàn)的時候需要注意,我們需要在parent外面再套一個容器,因為用table肯定會把parent設(shè)置成table,寬度是100%,沒辦法進行拓寬,再套一個容器的目的就是給他拓寬用的。

image-20200114171823653

我們思考一下,如果不在parent外面再套一層容器能不能解決?當然是能解決的,在外面再套一層容器的目的無非就是拓寬parent寬度,我們可以直接指定parent寬度為calc(100% + 20px),這樣實際的內(nèi)容會靠右20px,我們再用相對定位左移20px就行了:

.parent8 {
    display: table;
    width: calc(100% + 20px);
    table-layout: fixed;
  position: relative;
    left: -20px;
}

.column3 {
    display: table-cell;
    padding-left: 20px;
}

等寬:flex

用flex實現(xiàn)這個太簡單了,每個子元素都設(shè)置flex:1就行了。

image-20200114174136226

等高

等高布局要實現(xiàn)的就是當一列高度被撐高時,另一列也會跟著被撐高。

image-20200114174301840

等高:table

又是table,表格的一行里面不同的單元格天生就是等高的。

image-20200114175219551

這個方案里面table-layut:fixed;可以不設(shè)置。間距用透明的border-right來做。background-clip是一個CSS3屬性,表示背景要顯示到的區(qū)域,有三個值:

  • border-box: 背景被裁剪到邊框盒。
  • padding-box: 背景被裁剪到內(nèi)邊距框。
  • content-box: 背景被裁剪到內(nèi)容框。

等高:flex

萬能的flex又來了,也很簡單,跟前面定寬+自適應(yīng)的解決方案是一樣的。

image-20200114175737940

這是因為flex默認的align-items就是stretch,就是拉伸到充滿容器。

等高:float

前面的布局解決方案里面都有float,等高能用float解決嗎?答案是可以的,但是稍微麻煩點。在前面定寬+自適應(yīng)的基礎(chǔ)上給左右子元素都寫一個極大的padding-bottom,這樣兩個子元素的高度都很大了,然后我們用一個同樣的大的負的margin-bottom和父級的overflow:hidden將高度減回來。

image-20200114180646852

這樣做雖然左右子元素看起來是一樣高的,但是調(diào)試可以發(fā)現(xiàn),他們的高度已經(jīng)加了9999px,遠遠超過父容器了。這并不是真正意義上的等高,真正意義上的等高還是要用前面兩種方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 定寬+單列自適應(yīng)布局可以有如下幾種方式:1、設(shè)置left元素float:left; 并設(shè)置right的margin...
    Ryann閱讀 344評論 0 1
  • 在頁面開發(fā)中,當我們拿到設(shè)計師給出的UI圖后,首先考慮的就是布局問題,而多列布局會是我們碰到最多的布局問題,個人就...
    叫我叮當閱讀 1,186評論 0 1
  • 定義 BFC(Block formatting context)直譯為"塊級格式化上下文"。它是一個獨立的渲染區(qū)域...
    Arno_z閱讀 2,625評論 1 5
  • 這篇來說一下多列布局的后兩種-等分布局與等高布局。我們所說通常所說的等分布局如下: 也就是說最左邊會多出一個20p...
    Ryann閱讀 370評論 0 0
  • 前幾天我還過得好好的,可是不知怎么的?我今天早上起來發(fā)現(xiàn)嗓子都啞了。 然后看到媽媽在旁邊看手機,哎呀呀呀...
    落晚笙歌閱讀 353評論 0 1

友情鏈接更多精彩內(nèi)容