CSS佈局之三欄佈局

yvonneit發表於2019-03-17

前言

面試高頻考點,之前就記了個比較有名的聖盃佈局,沒想到面試官問了我上下欄固定、中間自適應的佈局,措手不及。藉此彌補下CSS佈局方面的知識。

(以下程式碼我都在瀏覽器上跑過,基本能夠實現佈局要求。)

上下固定,中間自適應

在網上找了下關於上中下佈局的文章,發現資料很少,所以總結的不是很好,如果大家有更完整、更優美的辦法可以在評論區留言。

<div class="top-center-bottom">
        <div class="top">top</div>
        <div class="center">center</div>
        <div class="bottom">bottom</div>
</div>
複製程式碼

position: absolute 定位

.top-center-bottom>div{
  position:absolute;
}
.top{
  top:0;
  height:100px;
  width:100%;
  background:red;
}
.bottom{
  bottom:0;
  height:100px;
  width:100%;
  background:red;
}
.center{
  bottom:100px;
  top:100px;
  width:100%;
  overflow: auto;
  background:green;
}
複製程式碼

overflow 屬性規定當內容溢位元素框時發生的事情。

overflow: auto; 如果內容被修剪,則瀏覽器會顯示滾動條以便檢視其餘的內容。 overflow: hidden; 內容會被修剪,並且其餘內容是不可見的。

使用彈性盒子flex

.top-center-bottom{
    display: flex;
    height: 100%; /*要指定高度*/
    flex-direction: column; /*佈局從上到下排列*/
}
.top,.bottom{
    display: flex;  /*這是為居中 文字的*/
    justify-content: center;  /*文字 水平居中*/
    align-items: center;   /*文字垂直居中*/
}
.top{
    height: 100px;
    background: #665aa4;
}
.center{
    flex-grow: 1; /*不知道和 flex: 1 有啥區別*/
    text-align: center;
    background: #3dc95d;
}
.bottom{
    height: 100px;
    background: #fc430b;
}
複製程式碼

flex-direction:colum; 使整體佈局從上到下排列

flex-grow:1; 應用於main,使得main自動填充剩餘空間

flex-grow的使用避免了當main內容過少時footer部分會被提升到頁面上方的問題(傳統方式上可能需要靠絕對定位來解決了~)

其他可做參考的寫法:

  <div class="container">
    <div class="flex-item">
      <div style="height: 100px;line-height: 100px;">top</div>
    </div>
    <div class="flex-item">
      <div style="height: 800px;color: #fff;">
        <div class="center">center</div>
      </div>
    </div>
    <div class="flex-item">
      <div style="height: 100px;line-height: 100px;">bottom</div>
    </div>
  </div>
複製程式碼
html, body{
  height:100%;
  margin: 0;
  padding: 0;
}
.container{
  height: 100%;
  display: flex;
  flex-direction: column;
  text-align: center;
}
.flex-item:nth-child(1), flex-item:nth-child(3){
  flex-grow:0;
  flex-shrink: 0;
  background-color: #ababab;
}
.flex-item:nth-child(2){
  flex-grow:1;
  flex-shrink: 1;
  background-color: #000;
  overflow-y: auto;
}
.center{
  position: fixed;
  top: 50%;
  left: 50%;
  margin-top: -10px;
  margin-left: -24px;
}
複製程式碼

flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 autoflex-basis指定了 flex 元素在主軸方向上的初始大小。

該屬性有兩個快捷值: auto (1 1 auto):元素會根據自身的寬度與高度來確定尺寸 none (0 0 auto):元素會根據自身寬高來設定尺寸

table / grid

因為太多了我也記不住,記住前兩個常用的應該就可以了。

左右固定,中間自適應

絕對定位法

<div class="left">Left</div>
<div class="main">Main</div>
<div class="right">Right</div>
複製程式碼
<!--簡單的進行CSS reset-->
body,html{
    height:100%;
    padding: 0px;
    margin:0px;
}
<!--左右絕對定位-->
.left,.right{
    position: absolute;
    top:0px;
    background: red;
    height:100%;
}
.left{
    left:0;
    width:100px;
}
.right{
    right:0px;
    width:200px;
}
<!--中間使用margin空出左右元素所佔據的空間-->
.main{
    margin:0px 200px 0px 100px;
    height:100%;
    background: blue;
}
複製程式碼

缺點:如果中間欄含有最小寬度限制,或是含有寬度的內部元素,當瀏覽器寬度小到一定程度,會發生層重疊的情況。

聖盃佈局

    <div class="container">
        <!-- 優先渲染 -->
        <div class="center">
            center
        </div>
        <div class="left">
            left
        </div>
        <div class="right">
            right
        </div>
    </div>
複製程式碼

使三欄浮動,並相對定位,給左右兩個容器設定200px的寬度、中間的容器設定100%的寬度。

body,html {
    height:100%;
    padding: 0;
    margin: 0
}
    .container {
        padding: 0 200px;
        height: 100%;
    }
    .container > div {
        position: relative;
        float: left;
        height: 100%;
    }
    .center {
        width: 100%;
        background-color: red;
    }
    .left {
        width: 200px;
        left: -200px;
        margin-left: -100%;
        background-color: green;
    }
    .right {
        width: 200px;
        right: -200px;
        margin-left: -200px;
        background-color: blue;
    }
複製程式碼

步驟:

  1. 由於浮動的關係,給 left 設定margin-left: -100%即可使左側欄浮動到 center 上面,並位於 center 左側之上。
  2. 同樣為 right 設定margin-left: -200px,這裡的長度等於 right 的長度
  3. 這時 center 的兩側被 left 和 right 覆蓋了,因此給 container設定padding: 0 200px
  4. 由於 left 和 right 也同時往中間縮,因此給 left 和 right 分別設定left: -200px; right: -200px,往兩側分別偏移自身的寬度去覆蓋掉 contaniner 使用padding後的空白位置。

相關解釋如下:

  1. 中間部分需要根據瀏覽器寬度的變化而變化,所以要用100%,這裡設左中右向左浮動,因為中間100%,左層和右層根本沒有位置上去
  2. 把左層margin負100後,發現left上去了,因為負到出視窗沒位置了,只能往上挪
  3. 按第二步這個方法,可以得出它只要挪動視窗寬度那麼寬就能到最左邊了,利用負邊距,把左右欄定位
  4. 但由於左右欄遮擋住了中間部分,於是採用相對定位方法,各自相對於自己把自己挪出去,得到最終結果

缺點:在視窗變小到限定值時佈局會亂掉,需要給它加上一個寬度限制min-width。而且聖盃佈局實際看起來是複雜的後期維護性也不是很高,在淘寶UED的探討下,出來了一種新的佈局方式就是雙飛翼佈局。

雙飛翼佈局

雙飛翼佈局給center 部分包裹了一個main,通過設定margin主動地把頁面撐開,為左右兩欄div留出位置。這時視窗寬度過小時就不會出現混亂的情況了。

<!-- 優先渲染 -->
    <div class="center">
        <div class="inner">
            center
        </div>
    </div>
複製程式碼
body,html {
    height:100%;
    padding: 0;
    margin: 0
}
.container {
    height: 100%;
}
.container > div{
        float: left;
        height: 100%;
    }
    .center {
        width: 100%;
        background-color: red;
    }
    .left {
        width: 200px;
        margin-left: -100%;
        background-color: green;
    }
    .right {
        width: 200px;
        margin-left: -200px;
        background-color: blue;
    }
    /*新增*/
    .inner {
        margin: 0 200px;
    }
複製程式碼

聖盃和雙飛翼佈局的不同在於解決“中間欄div內容不被遮擋”問題的思路不一樣:

聖盃佈局為了中間div內容不被遮擋,將父容器設定了左右padding-leftpadding-right後,將左右兩個div用相對佈局position:relative並分別配合right和left屬性,以便左右兩欄div移動後不遮擋中間div;

雙飛翼佈局為了中間div內容不被遮擋,直接在中間div內部建立子div用於放置內容,在該子div裡用margin-leftmargin-right為左右兩欄div留出位置。增加多一個div就可以不用相對佈局了,只用到了浮動和負邊距。

浮動

//注意元素次序
<div class="left">Left</div>
<div class="right">Right</div>
<div class="main">Main</div>
複製程式碼
body,html {
    height:100%;
    padding: 0;
    margin: 0
}
<!--左欄左浮動-->
.left {
    background: red;
    width: 100px;
    float: left;
    height: 100%;
}
<!--中間自適應-->
.main {
    background: blue;
    height: 100%;
    margin:0px 200px 0px 100px;
}
<!--右欄右浮動-->
.right {
    background: red;
    width: 200px;
    float: right;
    height: 100%;
}
複製程式碼

flex佈局

<div class="flex">
    <div class="left">left</div>
    <div class="main">middle</div>
    <div class="right">right</div>
</div>
複製程式碼
.flex {
    display: flex;
    flex-flow: row;
}
.left{
    width: 180px;
    height: 100px;    
    background-color: red;
}
.main{
    flex: 1; 
    height: 100px;
    background-color: blue;
}
.right {
    width: 200px;
    height: 100px;
    background-color: green;
}
複製程式碼

總結

左中右佈局的話記住三種應該就沒問題了,聖盃和雙飛翼佈局需要理解,別像我面試的時候只憋出來一個聖盃,還忘了具體怎麼實現......都是淚。

還有瀏覽器的適配問題,因為被問到了,頭疼......大家有時間的話自己可以搜一下,之後有時間的話我再補充吧,應付面試的話以上方法應該就夠了。

相關文章