Web自適應佈局你需要知道的所有事兒

TommyFu發表於2017-12-05

有這樣一個問題。

請說說你知道的所有web佈局方式?

一般來說,有以下這些佈局方法:

  1. 浮動 float:left|right
  2. inline-block display:inline-block
  3. flexible box display:flex
  4. grid display:grid
  5. 絕對、相對定位 position:absolute|relative
  6. 表格 <table>display:table
  7. 使用框架佈局 bootstrapPure.css

Web自適應佈局你需要知道的所有事兒

有小夥伴就要說,這也太多了吧,我應該怎麼選擇?

別急,下面我們就開始逐一分析各種方法在web自適應佈局下的使用姿勢,最後做個總結。


本文的所有例子使用了同一種三欄佈局。原始碼點我

  • 大尺寸 width > 1024px
  • 中尺寸 768px < width < 1024px
  • 小尺寸 width < 768px

Web自適應佈局你需要知道的所有事兒

1. 浮動佈局 float:left|right

最常用的佈局方式之一,設定了float的元素脫離了文件流。需要注意在使用過浮動後,需要清除浮動,從而避免影響後面的非浮動元素。

HTML

<div class="rwd-header">Header</div>
<div class="rwd-content">
  <div class="rwd-content-left">Left</div>
  <div class="rwd-content-body">
    <div class="rwd-content-bodyTop">Top Content</div>
    <div class="rwd-content-bodyBottom">Bottom Content</div>
  </div>
  <div class="rwd-content-right">Right</div>
</div>
<div class="rwd-footer">Footer</div>
複製程式碼

普通的html佈局,一個header,一個footer,中間是三欄式佈局。

關鍵css

.rwd-content-left,
.rwd-content-body,
.rwd-content-right {
  float: left;
}
複製程式碼

給中間的三欄都設上浮動。

.rwd-content::after {
  content: "";
  clear: both;
  display: block;
}
複製程式碼

清除浮動

.rwd-content-left {
  width: 20%;
  height: 200px;
}

.rwd-content-body {
  width: 60%;
}

.rwd-content-right {
  height: 300px;
  width: 20%;
}
複製程式碼

元素的寬度都是百分比。因為沒有內容高度給死了,日常應用時多用auto,讓裡面的內容撐開高度。


@media查詢

當@media的查詢條件滿足時,應用{}中的樣式。

screen就是指電腦螢幕,還有print指列印頁面。 MDN @media

@media做的事完全可以用javascript代替,用js新增一個class或者直接用js修改css屬性。優點是瀏覽器全相容,缺點就是用了js。


@media only screen and (max-width: 1024px) {
  .rwd-content-left {
    width: 30%;
  }
  .rwd-content-body {
    width: 70%;
  }
  .rwd-content-right {
    width: 100%;
  }
}

@media only screen and (max-width: 768px) {
  [class*="rwd-content-"] {
    width: 100%;
  }
}
複製程式碼

中尺寸螢幕要把right擠下去,只要讓leftcontent加起來等於100%,後面的東西就自動換行了。

小尺寸用了css選擇器,把所有rwd-content-開頭的class寬度都設成100%。

親自試一試


2. inline-block display:inline-block

HTML

<div class="rwd-header">Header</div>
<div class="rwd-content"
  ><div class="rwd-content-left">Left</div
    ><div class="rwd-content-body"
    ><div class="rwd-content-bodyTop">Top Content</div
    ><div class="rwd-content-bodyBottom">Bottom Content</div
  ></div
  ><div class="rwd-content-right">Right</div>
</div>
<div class="rwd-footer">Footer</div>
複製程式碼

html和浮動佈局的一樣,為了避免空白字元壓縮(white space collapse)的問題,寫法略有變化。

關鍵css

.rwd-content-left,
.rwd-content-body,
.rwd-content-right {
  display: inline-block;
  vertical-align: top;
}
複製程式碼

對我們這個佈局,只是把float:left改成這兩句。

自適應的程式碼也和float一樣,不重複貼了。

親自試一試


Float vs. Inline-block

兩者都是很常用的佈局方式。

  • 如果需要垂直居中,使用inline-block。

  • inline-block有空白字元壓縮的問題。

  • 使用float,注意要清除浮動。

  • 沒有特別推薦用哪種,看個人習慣。

如何調整float或inline-block佈局中元素的順序?

比如我在小尺寸的時候,想把content放最上面,left和right都擠下去,怎麼做呢?

float和inline-block佈局沒有純css的方法,要用js把dom扣出來,往後面放,flexbox和grid佈局都可以很好地解決這個問題。


3. flexible box display:flex

HTML

<div class="rwd-header">Header</div>
<div class="rwd-content">
  <div class="rwd-content-left">Left</div>
  <div class="rwd-content-body">
    <div class="rwd-content-bodyTop">Top Content</div>
    <div class="rwd-content-bodyBottom">Bottom Content</div>
  </div>
  <div class="rwd-content-right">Right</div>
</div>
<div class="rwd-footer">Footer</div>
複製程式碼

html還是一樣。

看css前先說說flex基礎。


* flexbox兩分鐘不完全指北

flexbox佈局說白了就是點菜。先想好要吃什麼,然後點必選菜,最後點可選菜,愛點不點。

先想要吃什麼,還是用之前的例子。header和footer不用管,需要佈局一個這樣的東西:

Web自適應佈局你需要知道的所有事兒

然後點必選菜,有下面幾個必選菜要點:

1). flex-direction, 選水平方向從左到右,選flex-direction: row

Web自適應佈局你需要知道的所有事兒

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
複製程式碼

2). flex-wrap,我們是單行佈局,不要換行,選flex-wrap: nowrap

Web自適應佈局你需要知道的所有事兒

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
複製程式碼

3). justify-content,如果水平方向有空間,怎麼分配,選space-between

Web自適應佈局你需要知道的所有事兒

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
複製程式碼

4). 垂直方向怎麼佈局,選align-items: flex-start

Web自適應佈局你需要知道的所有事兒

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
複製程式碼

5). align-content,多行佈局怎麼分配空間,我們是單行佈局,不存在的

Web自適應佈局你需要知道的所有事兒

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
複製程式碼

選好這5個之後,再加上display: flex;,往flex容器上一寫,就完事了。

可以偷懶的地方: 上面5種屬性,第一個值是預設值,如果選了第一個,這個屬性可以不用寫。

最後的可選菜比較常用的是可以調整flex子項(flex item)的順序(order),單獨改變某個子項的佈局等。

詳細教程點這裡flexbox中文教程[1] A Guide to Flexbox[2]


關鍵css

.rwd-content {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}
複製程式碼

flex容器(container)屬性如前文所說。

@media only screen and (max-width: 1024px) {
  .rwd-content {
    flex-wrap: wrap;
  }
  .rwd-content-left {
    width: 30%;
  }
  .rwd-content-body {
    width: 70%;
  }
  .rwd-content-right {
    width: 100%;
  }
}

@media only screen and (max-width: 768px) {
  [class*="rwd-content-"] {
    width: 100%;
  }
}
複製程式碼

自適應佈局時,設flex-wrap: wrap;,其他一樣。

親自試一試


Flexbox vs. Float/Inline-block

  • 如果瀏覽器沒問題,flexbox可以替代(或者替代大多數)float和inline-block。
  • 相比float,flexbox解決了垂直居中的問題。
  • 相比float/inline-block,flexbox多了垂直佈局的方式,可以使容器中的內容等高,還可以改變內容的順序。
  • flexbox就像名字一樣,非常靈活,同一種佈局都可以用多種方式實現。
  • flexbox的缺點是需要記的屬性比較多,小部分瀏覽器支援不好。

Can I use flex ?

Web自適應佈局你需要知道的所有事兒


4. grid佈局 display:grid

HTML

<div class="rwd-grid">
  <div class="rwd-header">Header</div>
  <div class="rwd-content-left">Left</div>
  <div class="rwd-content-bodyTop">Top Content</div>
  <div class="rwd-content-bodyBottom">Bottom Content</div>
  <div class="rwd-content-right">Right</div>
  <div class="rwd-footer">Footer</div>
</div>
複製程式碼

grid的特點就是為所欲為,dom的順序無所謂,只要放在grid容器下就可以。

看css之前還是先說說grid基礎。


* grid兩分鐘+兩分鐘不完全指北

2個兩分鐘因為一般grid有兩種使用方式:

1). 網格項(grid item)起個名字,在網格容器(grid container)上定義好網格佈局並且通過名字指定好所有網格項的位置。

2). 網格容器只定義佈局,每個網格項在使用的時候,自行選擇放到哪個(或哪幾個)網格中。

不管哪種方式,只要會劃線,你就掌握了grid佈局。把想要的佈局畫出來,然後用線分割開。

Web自適應佈局你需要知道的所有事兒

橫向1 ~ 7的黑線和縱向1) ~ 4)的紅線都叫網格線。

網格線包圍的一個或多塊矩形區域叫網格區塊。

第一種grid佈局方式:

.rwd-grid {
  display: grid;
  grid-gap: 5px;
  width: 100%;
  grid-template-areas: "header header header"
                        "left   top    right"
                        "left   bottom right"
                        ".      bottom right"
                        ".      bottom ."
                        "footer footer footer";
  grid-template-rows: 80px 150px 50px 100px 100px 100px;
  grid-template-columns: 20% 60% 20%;
}

.rwd-header {
  grid-area: header;
}
.rwd-content-left {
  grid-area: left;
}
.rwd-content-bodyTop {
  grid-area: top;
}
.rwd-content-bodyBottom {
  grid-area: bottom;
}
.rwd-content-right {
  grid-area: right;
}
.rwd-footer {
  grid-area: footer;
}
複製程式碼

網格項(grid item)用grid-area屬性起個名字。

網格容器(grid container)上三個主要屬性要設定:

grid-template-areas: 就是一張地圖,和我們劃線分割的圖佈局一樣,.表示空白。

grid-template-rows: 設定行上的高度,不設定的話為auto。除了固定數字,百分比還有fr。 grid-template-rows: repeat(3, 1fr)就是三等分的意思。

grid-template-columns: 設定列的寬度。

自適應佈局就是重畫地圖。

@media only screen and (max-width: 1024px) {
  .rwd-grid {
    grid-template-areas: "header header"
                          "left   top"
                          "left   bottom"
                          ".      bottom"
                          "right  right"
                          "footer footer";
    grid-template-rows: 80px 150px 50px 200px 100px 100px;
    grid-template-columns: 30% 70%;
  }
}

@media only screen and (max-width: 768px) {
  .rwd-grid {
    grid-template-areas: "header"
                          "left"
                          "top"
                          "bottom"
                          "right"
                          "footer";
    grid-template-rows: 80px 200px 150px 250px 100px 100px;
    grid-template-columns: 100%;
  }
}
複製程式碼

親自試一試1


第二種grid佈局方式:

.rwd-grid {
  display: grid;
  grid-gap: 5px;
  margin: 5px 0;
  width: 100%;
  grid-template-rows: 80px 150px 50px repeat(3, 100px);
  grid-template-columns: 20% 60% 20%;
}
複製程式碼

網格容器上只要設定grid-template-rowsgrid-template-columns。網格項在用的時候,自行設定需要放的地方。有很多種設定方式。

.rwd-header {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 2;
}
複製程式碼

四個屬性,分別是行、列的開始和結束。這邊的序號指的是網格線,參照之前圖中橫向的黑色網格線和縱向的紅色網格線。

參照圖,應該好理解。

相當於:

.rwd-header {
  grid-column: 14;
  grid-row: 12;
}
複製程式碼

簡寫成兩個屬性,<開始> / <結束>。

相當於:

.rwd-header {
  grid-column: 1 / span 3;
  grid-row: 1;
}
複製程式碼

span 3指的是經過了3個網格;如果網格項只跨越了1格,可以省略設定結束位置的網格線。

相當於:

.rwd-header {
  grid-area: 1 / 1 / 2 / 4;
}
複製程式碼

網格線上左下右的順序,不同於margin和padding的上右下左。

當然你可以別管這麼多亂七八糟的,看我自適應佈局:

@media only screen and (max-width: 1024px) {
  .rwd-grid {
    grid-template-rows: 80px 150px 50px 200px 100px 100px;
    grid-template-columns: 30% 70%;
  }

  .rwd-header {
    grid-area: 1 / 1 / 2 / 3;
  }
  .rwd-content-left {
    grid-area: 2 / 1 / 4 / 2;
  }
  .rwd-content-bodyTop {
    grid-area: 2 / 2 / 3 / 3;
  }
  .rwd-content-bodyBottom {
    grid-area: 3 / 2 / 5 / 3;
  }
  .rwd-content-right {
    grid-area: 5 / 1 / 6 / 3;
  }
  .rwd-footer {
    grid-area: 6 / 1 / 7 / 3;
  }
}
複製程式碼

親自試一試2

詳細教程點這裡網格中基於線的定位[3] 和這裡 網格模板區域[4]


Grid vs. Flexbox

  • flexbox是單方向的,橫向或者縱向,grid是二維的。
  • grid就是可以為所欲為,甚至和html的順序沒有關係,只要扔到grid容器裡就可以。
  • grid能做到flexbox做不到的事,反之亦然。如果瀏覽器支援,最好結合兩者使用。
  • grid適合佈局大的骨架,flexbox適合佈局區域性。
  • grid的最大缺點是瀏覽器支援不是很好。
  • grid另一個缺點是,如果要往現有的佈局里加一點或者刪一點東西,基本就是重畫了,其實也不算缺點,因為重畫很快。
  • grid不適合複雜的佈局,因為網格線太多我頭暈。
  • grid小技巧,用chrome和firefox的除錯工具檢視grid容器可以看到網格,光看程式碼要瘋。

Can I use grid ?

Web自適應佈局你需要知道的所有事兒


5. 絕對、相對定位 position:absolute|relative

相當常用,特別是各種特效裡都會用到。

對於自適應佈局,就自己算topleft吧。


6. 表格 <table>display:table

個人認為表格佈局比較適用於表格(看上去是廢話,但並不是)。

如果是一般的頁面佈局,就不要用table了。Why not use tables for layout in HTML?[5]

關於表格的自適應,看這裡:Responsive table layout[6]


7. 使用框架佈局 bootstrapPure.css

所謂萬變不離其宗,用框架佈局也是使用了上面所說的原理,這邊就不再細說各種框架。


* IE盒模型

推薦給所有元素加上border-box;

* {
  box-sizing: border-box;
}
複製程式碼

IE盒模型的寬度和高度包括了padding和border,這樣對於百分比的佈局比較好控制,不會出現加起來超過100%而換行的情況。


* 儘量不使用固定高度、寬度

在自適應的佈局中少用或者不用固定的高度、寬度,使用百分比, auto或calc()。


* viewport

<meta name="viewport" content="width=500, initial-scale=1">
複製程式碼

viewport主要用於手機自適應佈局,因為現在手機解析度越來越高,web上的1px到手機上未必就是1px,用這個meta讓手機的px和web的px保持一致。

具體解釋在這裡: viewport meta[7]


說到這裡,看完的同學應該都明白了web自適應佈局常見的套路。

Web自適應佈局你需要知道的所有事兒

當碰到某個酷炫的自適應頁面的時候至少不會說: 這個怎麼實現的?還有這種操作?

最後總結一下:

自適應佈局需要注意的事:

  1. 使用IE盒模型box-sizing: border-box
  2. 不要用固定寬高,使用百分比, auto或calc()
  3. @media是自適應佈局利器
  4. 手機上要設定meta viewport
  5. 關於各種佈局的選擇: 在瀏覽器支援的情況下,頁面的大框架推薦用grid佈局。定好架子後,區域性佈局推薦用flex。 float和inline-block瀏覽器支援好,但各有缺點。

那麼有同學就要問,是不是隻要學flex和grid就行了?對不起,所有都要學(就是這麼可怕)。各種佈局都有他們的使用場景。並且你也攔不住別人用,都需要看懂是吧。只能說要與時俱進,路漫漫其修遠兮,吾將上下而求索。


參考資料

[1] Flex佈局教程 - http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

[2] A Complete Guide to Flexbox - https://css-tricks.com/snippets/css/a-guide-to-flexbox/

[3] CSS網格中基於線的定位 - https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid

[4] 網格模板區域 - https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout/Grid_Template_Areas

[5] Why not use tables for layout in HTML? - https://stackoverflow.com/questions/83073/why-not-use-tables-for-layout-in-html

[6] Responsive table layout - http://allthingssmitty.com/2016/10/03/responsive-table-layout/

[7] Using the viewport meta tag to control layout on mobile browsers - https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag

[8] Responsive Web Design - https://www.w3schools.com/css/css_rwd_intro.asp

[9] Can I use - https://caniuse.com/

相關文章