舊版佈局方法
網格系統是 CSS 佈局中非常常見的功能。在 CSS 網格佈局出現之前,它們通常使用浮動或其他佈局功能來實現。您將佈局想象成一組固定數量的列(例如 4、6 或 12),然後將您的內容列放入這些假想的列中。在本文中,我們將探討這些舊方法是如何工作的,以便您在處理舊專案時瞭解它們是如何使用的。
CSS 網格佈局之前的佈局和網格系統
對於有設計背景的人來說,CSS 直到最近才內建網格系統,這可能令人驚訝。相反,我們似乎一直在使用各種次優方法來建立類似網格的設計。我們現在將這些方法稱為“傳統”方法。
對於新專案,在大多數情況下,CSS 網格佈局將與一種或多種其他現代佈局方法結合使用,作為任何佈局的基礎。但是,您會不時遇到使用這些傳統方法的“網格系統”。瞭解它們的工作原理以及它們與 CSS 網格佈局的不同之處是值得的。
本課程將解釋基於浮動和 Flexbox 的網格系統和網格框架是如何工作的。學習了網格佈局後,您可能會驚訝於這一切看起來多麼複雜!如果您需要為不支援新方法的瀏覽器建立備用程式碼,以及允許您處理使用這些型別系統的現有專案,這些知識將對您有所幫助。
在探索這些系統時,值得記住的是,它們都沒有以 CSS 網格佈局建立網格的方式實際建立網格。它們透過給專案一個大小並將它們推來推去以使其對齊,從而看起來像一個網格。
兩列布局
讓我們從最簡單的例子開始——兩列布局。您可以按照以下步驟操作:在您的計算機上建立一個新的 index.html 檔案,用一個 簡單的 HTML 模板 填充它,然後將以下程式碼插入到適當的位置。在本節的底部,您可以看到最終程式碼的即時示例。
首先,我們需要一些內容放入我們的列中。將主體中當前的所有內容替換為以下內容
<h1>2 column layout example</h1>
<div>
<h2>First column</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus
aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci,
pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at
ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer
ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur
vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus.
Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus
sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus.
Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis,
eget fermentum sapien.
</p>
</div>
<div>
<h2>Second column</h2>
<p>
Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada
ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed
est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus
tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies
lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis
vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus mus.
</p>
</div>
每個列都需要一個外部元素來包含其內容,並讓我們一次性操作所有內容。在此示例中,我們選擇了 <div>,但您可以選擇更具語義的元素,例如 <article>、<section> 和 <aside> 等。
現在是 CSS。首先,將以下內容應用於您的 HTML 以提供一些基本設定
body {
width: 90%;
max-width: 900px;
margin: 0 auto;
}
主體將佔據視口寬度的 90%,直到它達到 900 畫素寬,此時它將保持這個寬度並居中在視口中。預設情況下,它的子元素(h1 和兩個 <div>)將佔據主體寬度的 100%。如果我們要讓這兩個 <div> 彼此浮動,我們需要將它們的寬度設定為其父元素總寬度的 100% 或更小,以便它們可以彼此並排排列。將以下內容新增到您的 CSS 底部
div:nth-of-type(1) {
width: 48%;
}
div:nth-of-type(2) {
width: 48%;
}
在這裡,我們都將它們設定為其父級寬度的 48%——總計 96%,剩下 4% 的空間作為兩列之間的間距,讓內容有一些呼吸空間。現在我們只需浮動這些列,如下所示
div:nth-of-type(1) {
width: 48%;
float: left;
}
div:nth-of-type(2) {
width: 48%;
float: right;
}
將所有這些放在一起應該會得到如下結果
您會注意到這裡我們所有的寬度都使用了百分比——這是一個相當不錯的策略,因為它建立了一個**流體佈局**,一個可以適應不同螢幕尺寸並在較小螢幕尺寸下保持相同列寬比例的佈局。嘗試調整瀏覽器視窗的寬度,親自看看。這是響應式網頁設計的一個有價值的工具。
注意:您可以在 0_two-column-layout.html 檢視此示例(另請參閱原始碼)。
建立簡單的傳統網格框架
大多數傳統框架都利用 float 屬性的行為,將一列浮動到另一列旁邊,以建立類似網格的東西。透過建立浮動網格的過程,您可以瞭解其工作原理,並引入一些更高階的概念,以在您在關於 浮動和清除 的課程中學到的知識上進行構建。
最容易建立的網格框架是固定寬度的——我們只需要計算出我們設計的總寬度、我們想要的列數以及間距和列的寬度。如果我們決定將設計佈局在一個網格上,其列根據瀏覽器寬度而增長和收縮,那麼我們需要計算列的百分比寬度以及它們之間的間距。
在接下來的部分中,我們將探討如何建立這兩種網格。我們將建立一個 12 列網格——這是一個非常常見的選擇,鑑於 12 可以被 6、4、3 和 2 整除,因此被認為非常適合不同的情況。
一個簡單的固定寬度網格
我們先建立一個使用固定寬度列的網格系統。
首先,複製我們的示例 simple-grid.html 檔案,其中包含以下標記。
<div class="wrapper">
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
<div class="col">6</div>
<div class="col">7</div>
<div class="col">8</div>
<div class="col">9</div>
<div class="col">10</div>
<div class="col">11</div>
<div class="col">12</div>
</div>
<div class="row">
<div class="col span1">13</div>
<div class="col span6">14</div>
<div class="col span3">15</div>
<div class="col span2">16</div>
</div>
</div>
目標是將其轉換為一個十二列網格上的兩行演示網格——頂行演示單個列的大小,第二行演示網格上不同大小的區域。

在 <style> 元素中,新增以下程式碼,它為包裝容器提供了 980 畫素的寬度,右側填充 20 畫素。這使我們總共有 960 畫素用於我們的總列/間距寬度——在這種情況下,填充是從總內容寬度中減去的,因為我們將 box-sizing 設定為站點上所有元素的 border-box(有關更多解釋,請參閱 替代 CSS 盒模型)。
* {
box-sizing: border-box;
}
body {
width: 980px;
margin: 0 auto;
}
.wrapper {
padding-right: 20px;
}
現在使用包裹每行網格的行容器來清除一行和另一行。在您之前的規則下面新增以下規則
.row {
clear: both;
}
應用此清除意味著我們不需要用完整的十二列元素完全填充每一行。行將保持分離,並且不會相互干擾。
列之間的間距為 20 畫素寬。我們透過在每個列的左側建立邊距來建立這些間距——包括第一列,以平衡容器右側 20 畫素的填充。所以我們總共有 12 個間距——12 x 20 = 240。
我們需要從總寬度 960 畫素中減去這個值,這樣我們的列就剩下 720 畫素。如果我們現在將這個值除以 12,我們知道每個列的寬度應該是 60 畫素。
我們的下一步是為類 .col 建立一個規則,將其左浮動,為其提供 20 畫素的 margin-left 以形成間距,以及 60 畫素的 width。將以下規則新增到您的 CSS 底部
.col {
float: left;
margin-left: 20px;
width: 60px;
background: rgb(255 150 150);
}
頂部的單列現在將整齊地排列成一個網格。
注意:我們還為每列指定了淺紅色,這樣您就可以確切地看到每列佔用了多少空間。
我們希望跨越多列的佈局容器需要賦予特殊的類,以將其 width 值調整為所需的列數(加上之間的間距)。我們需要建立一個額外的類,以允許容器跨越 2 到 12 列。每個寬度都是該列數的列寬加上間距寬度的結果,間距寬度總是比列數少一個。
將以下內容新增到您的 CSS 底部
/* Two column widths (120px) plus one gutter width (20px) */
.col.span2 {
width: 140px;
}
/* Three column widths (180px) plus two gutter widths (40px) */
.col.span3 {
width: 220px;
}
/* And so on… */
.col.span4 {
width: 300px;
}
.col.span5 {
width: 380px;
}
.col.span6 {
width: 460px;
}
.col.span7 {
width: 540px;
}
.col.span8 {
width: 620px;
}
.col.span9 {
width: 700px;
}
.col.span10 {
width: 780px;
}
.col.span11 {
width: 860px;
}
.col.span12 {
width: 940px;
}
建立這些類後,我們現在可以在網格上佈局不同寬度的列。嘗試儲存並在瀏覽器中載入頁面以檢視效果。
嘗試修改元素上的類,甚至新增和刪除一些容器,以檢視如何改變佈局。例如,您可以使第二行看起來像這樣
<div class="row">
<div class="col span8">13</div>
<div class="col span4">14</div>
</div>
現在您已經擁有一個工作的網格系統,您可以定義行和每行中的列數,然後用所需內容填充每個容器。太棒了!
建立流體網格
我們的網格執行良好,但它是固定寬度的。我們真正想要的是一個靈活(流體)的網格,它會隨著瀏覽器 視口 中的可用空間而增長和收縮。為了實現這一點,我們可以將參考畫素寬度轉換為百分比。
將固定寬度轉換為基於百分比的靈活寬度的公式如下。
target / context = result
對於我們的列寬,我們的**目標寬度**是 60 畫素,我們的**上下文**是 960 畫素的包裝器。我們可以使用以下公式計算百分比。
60 / 960 = 0.0625
然後我們將小數點向右移動 2 位,得到 6.25% 的百分比。因此,在我們的 CSS 中,我們可以用 6.25% 替換 60 畫素的列寬。
我們還需要對我們的間距寬度做同樣的事情
20 / 960 = 0.02083333333
所以我們需要將 .col 規則上的 20 畫素 margin-left 和 .wrapper 上的 20 畫素 padding-right 替換為 2.08333333%。
更新我們的網格
要開始本節,請製作您上一個示例頁面的新副本,或製作我們的 simple-grid-finished.html 程式碼的本地副本作為起點。
如下更新第二條 CSS 規則(帶有 .wrapper 選擇器)
body {
width: 90%;
max-width: 980px;
margin: 0 auto;
}
.wrapper {
padding-right: 2.08333333%;
}
我們不僅為其設定了百分比 width,還添加了 max-width 屬性,以防止佈局變得太寬。
接下來,像這樣更新第四個 CSS 規則(帶有 .col 選擇器)
.col {
float: left;
margin-left: 2.08333333%;
width: 6.25%;
background: rgb(255 150 150);
}
現在是稍微費力一點的部分——我們需要將所有的 .col.span 規則更新為使用百分比而不是畫素寬度。這需要用計算器花一點時間;為了省去您的麻煩,我們已經在下面為您完成了。
用以下內容更新 CSS 規則的底部塊
/* Two column widths (12.5%) plus one gutter width (2.08333333%) */
.col.span2 {
width: 14.58333333%;
}
/* Three column widths (18.75%) plus two gutter widths (4.1666666) */
.col.span3 {
width: 22.91666666%;
}
/* And so on… */
.col.span4 {
width: 31.24999999%;
}
.col.span5 {
width: 39.58333332%;
}
.col.span6 {
width: 47.91666665%;
}
.col.span7 {
width: 56.24999998%;
}
.col.span8 {
width: 64.58333331%;
}
.col.span9 {
width: 72.91666664%;
}
.col.span10 {
width: 81.24999997%;
}
.col.span11 {
width: 89.5833333%;
}
.col.span12 {
width: 97.91666663%;
}
現在儲存你的程式碼,在瀏覽器中載入它,然後嘗試改變視口寬度——你應該會看到列寬很好地調整以適應。
使用 calc() 函式進行更簡單的計算
您可以使用 calc() 函式在 CSS 中直接進行計算——這允許您在 CSS 值中插入簡單的數學方程式,以計算一個值應該是什麼。當需要進行復雜的數學運算時,它特別有用,您甚至可以計算使用不同單位的計算,例如“我希望這個元素的高度始終是其父元素高度的 100%,減去 50 畫素”。請參閱 此 MediaStream Recording API 教程中的示例。
言歸正傳,回到我們的網格!任何跨越網格中多於一列的列的總寬度是 6.25% 乘以跨越的列數,加上 2.08333333% 乘以間距數(間距數總是比列數少 1)。 calc() 函式允許我們在寬度值中直接進行此計算,例如,對於跨越 4 列的任何專案,我們可以這樣做
.col.span4 {
width: calc((6.25% * 4) + (2.08333333% * 3));
}
嘗試用以下內容替換您的底部規則塊,然後在瀏覽器中重新載入以檢視是否得到相同的結果
.col.span2 {
width: calc((6.25% * 2) + 2.08333333%);
}
.col.span3 {
width: calc((6.25% * 3) + (2.08333333% * 2));
}
.col.span4 {
width: calc((6.25% * 4) + (2.08333333% * 3));
}
.col.span5 {
width: calc((6.25% * 5) + (2.08333333% * 4));
}
.col.span6 {
width: calc((6.25% * 6) + (2.08333333% * 5));
}
.col.span7 {
width: calc((6.25% * 7) + (2.08333333% * 6));
}
.col.span8 {
width: calc((6.25% * 8) + (2.08333333% * 7));
}
.col.span9 {
width: calc((6.25% * 9) + (2.08333333% * 8));
}
.col.span10 {
width: calc((6.25% * 10) + (2.08333333% * 9));
}
.col.span11 {
width: calc((6.25% * 11) + (2.08333333% * 10));
}
.col.span12 {
width: calc((6.25% * 12) + (2.08333333% * 11));
}
注意:您可以在 fluid-grid-calc.html 中檢視我們完成的版本(另請參閱 即時執行)。
語義與“非語義”網格系統
向標記新增類來定義佈局意味著您的內容和標記與您的視覺呈現繫結在一起。您有時會聽到這種 CSS 類用法被描述為“非語義”——描述內容的外觀——而不是描述內容的語義類用法。我們的 span2、span3 等類就是這種情況。
這些並非唯一的方法。您可以改為確定您的網格,然後將尺寸資訊新增到現有語義類的規則中。例如,如果您有一個帶有 content 類的 <div>,您希望它跨越 8 列,您可以從 span8 類複製寬度,從而得到如下規則
.content {
width: calc((6.25% * 8) + (2.08333333% * 7));
}
注意:如果您使用 Sass 等預處理器,您可以建立一個簡單的混入來為您插入該值。
在我們的網格中啟用偏移容器
我們建立的網格在所有容器都與網格左側齊平的情況下執行良好。如果我們在第一個容器之前或容器之間留出一個空的列空間,我們就需要建立一個偏移類,為我們的站點新增左外邊距,以在視覺上將其推過網格。更多數學!
我們來試試看。
從您之前的程式碼開始,或者使用我們的 fluid-grid.html 檔案作為起點。
讓我們在 CSS 中建立一個類,它將容器元素偏移一個列寬。將以下內容新增到您的 CSS 底部
.offset-by-one {
margin-left: calc(6.25% + (2.08333333% * 2));
}
或者如果您喜歡自己計算百分比,請使用此公式
.offset-by-one {
margin-left: 10.41666666%;
}
現在您可以將此類別新增到任何您希望在其左側留出單列寬空白空間的容器中。例如,如果您的 HTML 中有以下內容
<div class="col span6">14</div>
嘗試將其替換為
<div class="col span5 offset-by-one">14</div>
注意:請注意,您需要減少跨越的列數,以為偏移留出空間!
嘗試載入和重新整理以檢視差異,或者檢視我們的 fluid-grid-offset.html 示例(也請參閱 即時執行)。完成的示例應如下所示
![]()
注意:作為一項額外的練習,您能否實現一個 offset-by-two 類?
浮動網格的侷限性
使用這樣的系統時,您確實需要注意總寬度是否正確相加,並且不要在一行中包含跨越列數超出該行所能包含的列數的元素。由於浮動的工作方式,如果網格的列數對於網格來說太寬,則末尾的元素將下降到下一行,從而破壞網格。
還要記住,如果元素的內容比它們所佔的行更寬,它將溢位並看起來一團糟。
該系統最大的限制在於它本質上是**一維**的。我們處理的是列,以及跨列的元素,而不是行。使用這些舊的佈局方法很難控制元素的高度,除非明確設定高度,這也不是一種靈活的方法——它只在您能保證內容具有特定高度時才有效。
Flexbox 網格?
如果您閱讀了我們之前關於 flexbox 的文章,您可能會認為 flexbox 是建立網格系統的理想解決方案。有許多基於 flexbox 的網格系統可用,並且 flexbox 可以解決我們在上面建立網格時已經發現的許多問題。
然而,flexbox 從未被設計為網格系統,當用作網格系統時,它帶來了一系列新的挑戰。作為一個簡單的例子,我們可以使用上面相同的示例標記,並使用以下 CSS 來樣式化 wrapper、row 和 col 類
body {
width: 90%;
max-width: 980px;
margin: 0 auto;
}
.wrapper {
padding-right: 2.08333333%;
}
.row {
display: flex;
}
.col {
margin-left: 2.08333333%;
margin-bottom: 1em;
width: 6.25%;
flex: 1 1 auto;
background: rgb(255 150 150);
}
您可以在自己的示例中嘗試進行這些替換,或者檢視我們的 flexbox-grid.html 示例程式碼(另請參閱 即時執行)。
在這裡,我們將每一行都變成了一個彈性容器。對於基於彈性盒的網格,我們仍然需要行,以便允許我們擁有總和小於 100% 的元素。我們將該容器設定為 display: flex。
在 .col 上,我們將 flex 屬性的第一個值(flex-grow)設定為 1,以便我們的專案可以增長;將第二個值(flex-shrink)設定為 1,以便專案可以收縮;將第三個值(flex-basis)設定為 auto。由於我們的元素設定了 width,auto 將使用該寬度作為 flex-basis 值。
在第一行中,我們得到了十二個整齊的網格框,並且它們隨著我們改變視口寬度而均勻地增長和收縮。然而,在下一行中,我們只有四個專案,它們也從 60px 的基準開始增長和收縮。由於只有四個專案,它們可以比上面一行中的專案增長更多,結果是它們在第二行中都佔據相同的寬度。

為了解決這個問題,我們仍然需要包含我們的 span 類,以提供一個寬度來替換該元素用於 flex-basis 的值。
它們也不遵循上面專案使用的網格,因為它們對它一無所知。
Flexbox 在設計上是**一維**的。它處理的是單維度,即行或列。我們無法為列和行建立嚴格的網格,這意味著如果我們要在網格中使用 flexbox,我們仍然需要像浮動佈局那樣計算百分比。
在您的專案中,您可能仍然會選擇使用 flexbox“網格”,因為 flexbox 比浮動提供了額外的對齊和空間分佈功能。但是,您應該意識到,您仍然在使用一個並非為此目的設計的工具。因此,您可能會覺得它讓您需要進行額外的操作才能達到您想要的結果。
第三方網格系統
既然我們已經瞭解了網格計算背後的數學原理,那麼我們就可以很好地研究一些常用的第三方網格系統了。如果您在網上搜索“CSS 網格框架”,您會發現大量的選擇。像 Bootstrap 和 Foundation 這樣的流行框架都包含網格系統。還有獨立的網格系統,它們使用 CSS 或預處理器開發。
讓我們來看看其中一個獨立的系統,因為它展示了使用網格框架的常用技術。我們將使用的網格是 Skeleton(一個簡單的 CSS 框架)的一部分。
首先訪問 Skeleton 網站,然後選擇“下載”以下載 ZIP 檔案。解壓此檔案,並將 skeleton.css 和 normalize.css 檔案複製到一個新目錄中。
複製我們的 html-skeleton.html 檔案,並將其儲存在與 skeleton 和 normalize CSS 相同的目錄中。
透過在 HTML 頁面的 head 中新增以下內容,將 skeleton 和 normalize CSS 包含到 HTML 頁面中
<link href="normalize.css" rel="stylesheet" />
<link href="skeleton.css" rel="stylesheet" />
Skeleton 不僅僅包含一個網格系統——它還包含用於排版和其他頁面元素的 CSS,您可以將其作為起點。不過,我們暫時將這些保留為預設值——我們真正感興趣的是網格。
注意: Normalize 是 Nicolas Gallagher 編寫的一個非常有用的小型 CSS 庫,它會自動進行一些有用的基本佈局修復,並使預設元素樣式在不同瀏覽器中更加一致。
我們將使用與之前示例類似的 HTML。將以下內容新增到您的 HTML 主體中
<div class="container">
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
<div class="col">6</div>
<div class="col">7</div>
<div class="col">8</div>
<div class="col">9</div>
<div class="col">10</div>
<div class="col">11</div>
<div class="col">12</div>
</div>
<div class="row">
<div class="col">13</div>
<div class="col">14</div>
<div class="col">15</div>
<div class="col">16</div>
</div>
</div>
要開始使用 Skeleton,我們需要為包裝器 <div> 新增一個 container 類——這已經包含在我們的 HTML 中。它將內容居中,最大寬度為 960 畫素。您可以看到這些框現在永遠不會超過 960 畫素寬。
您可以在 skeleton.css 檔案中檢視當我們應用此類別時使用的 CSS。該 <div> 使用 auto 左右邊距居中,並應用 20 畫素的左右填充。Skeleton 還將 box-sizing 屬性設定為 border-box,就像我們之前所做的那樣,因此該元素的填充和邊框將包含在總寬度中。
.container {
position: relative;
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box;
}
元素只能是網格的一部分,如果它們在一個行內,因此與我們之前的示例一樣,我們需要一個額外的 <div> 或其他元素,其類為 row,巢狀在內容 <div> 元素和容器 <div> 之間。我們也已經這樣做了。
現在我們來佈置容器盒。Skeleton 基於 12 列網格。頂部行中的所有盒都需要 one column 類,使它們跨越一列。
現在新增這些,如下面的程式碼片段所示
<div class="container">
<div class="row">
<div class="one column">1</div>
<div class="one column">2</div>
<div class="one column">3</div>
/* and so on */
</div>
</div>
接下來,為第二行中的容器新增類,說明它們應該跨越的列數,如下所示
<div class="row">
<div class="one column">13</div>
<div class="six columns">14</div>
<div class="three columns">15</div>
<div class="two columns">16</div>
</div>
嘗試儲存您的 HTML 檔案並在瀏覽器中載入它以檢視效果。
注意:如果您在使此示例正常工作時遇到問題,請嘗試加寬用於檢視它的視窗(如果視窗太窄,網格將不會像此處描述的那樣顯示)。如果這不起作用,請嘗試將其與我們的 html-skeleton-finished.html 檔案進行比較(也請參閱 即時執行)。
如果你檢視 skeleton.css 檔案,你就能看到它是如何工作的。例如,Skeleton 定義了以下內容來樣式化添加了“三列”類的元素。
.three.columns {
width: 22%;
}
Skeleton(或任何其他網格框架)所做的只是設定預定義的類,您可以透過將它們新增到您的標記來使用它們。這與您自己計算這些百分比的工作完全相同。
如您所見,在使用 Skeleton 時,我們幾乎不需要編寫任何 CSS。當我們向標記新增類時,它會為我們處理所有的浮動。正是這種將佈局責任交給其他東西的能力使得使用框架作為網格系統成為一個引人注目的選擇!然而,如今,隨著 CSS 網格佈局的出現,許多開發人員正在放棄這些框架,轉而使用 CSS 提供的內建原生網格。
總結
您現在已經瞭解了各種網格系統是如何建立的,這對於處理舊站點以及理解 CSS 網格佈局的本機網格與這些舊系統之間的差異將非常有用。