翻譯 | CSS網格(CSS Grid)布局入門

翻譯 | CSS網格(CSS Grid)布局入門

banner

CSS網格布局是瀏覽器Flexbox布局之后最重要的布局方式。我們可以忘記過去15年經常使用的的各種“神奇數字”,hacks和一系列變通布局方案。網格布局提供了非常簡單的聲明布局方式,之后再也不需要借助一些常見的主流css框架,也能減少很多手動實現的布局方式

如果你以前不熟悉CSS網格布局,那么你可以開始了解它了。它是一種適用于容器元素,并能指定子元素的間距、大小和對齊方式的布局工具。

CSS網格布局賦予我們更強大的能力——大家熟悉的水平垂直居中布局,不需要增加標簽就能做到。同樣,這也能讓我們不需要媒體查詢就能根據可用空間自動適應。

學習的最低要求

首先網格布局有不少新語法需要學習,但是你只需要稍微看下就能上手。本文將會用示例帶你學習CSS網格布局各種各樣重要的入門概念。

瀏覽器兼容性

CSS網格布局從Safari 10.1, Firefox 52, Opera 44, Chrome 57開始收到支持,微軟Edge在Edge 15會更新對網格布局的支持。

微軟的瀏覽器(IE10–11和Edge 13-14)有一種比較舊的實現,所以有不少限制,我們會簡單介紹新的實現方式和老的實現方式之間的區別,這樣你能知道如何規避他們。

對于大多數布局,我們會使用下面的query特性來讓老的瀏覽器對他們理解的特性也能工作:

@supports (display: grid) {
    .grid {
        display: grid;
    }
}

不支持瀏覽器@supports或網格的瀏覽器將不會生效。

為了能正確展示文中的示例,你需要使用支持網格布局的瀏覽器

創建帶有間距(gutter)的兩列(column)網格

為了演示CSS網格布局如何定義列,我們從下面的布局開始:


grid-template-columns 和 grid-gap

[使用grid-template-columns 和 grid-gap創建帶間距的兩列布局]

為了創建上述網格布局,我們需要使用grid-template-columnsgrid-gap
grid-template-columns表示網格中的列是如何布局的,它的值是一連串以空格分割的的值,這些值標識每列的大小,值的個數表示列的數目。

例如,四列250px寬度的網格布局可以這樣表示:

grid-template-columns: 250px 250px 250px 250px;

也可以使用repeat關鍵字表示:

grid-template-columns: repeat(4, 250px);

定義間距

grid-gap定義了網格布局的間距大小,接收一個或兩個值,如果定義兩個值則表示列(column)和行(row)的間距大小。

在兩列布局示例中,我們可以如下使用:

.grid {
  display: grid;
  grid-template-columns: 50vw 50vw;
  grid-gap: 1rem;
}

不幸的是,這個間距將會占用容器元素的整體寬度,計算出來就是100vw + 1rem,最終這個布局會導致出現水平滾動條。

viewport導致的水平滾動條

[通過viewport單位創建帶間距網格導致的水平滾動條]

為了解決這個空間溢出問題,我們需要些不同的方法來處理,需要用分數單位或者說是FR

分數單位

分數單位標識占用可用空間的份額,如果900px是可用空間,其中的一個元素占有1份,另外的元素占有2份——那么第一個元素的寬度會是900px的1/3,另外的元素是900px的2/3。
修改后用分數代替view-port單位的新代碼如下:

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 1rem;
}

內容對齊

為了對齊示例中的內容,我們在子元素上使用grid布局,并加上對齊屬性來定位他們到指定軌道(track),軌道就是一個網格的列或行的某個位置的常見的名稱。網格跟Flex布局一樣,有一系列對齊的屬性——共有四種值——start, center, end, 和stretch,分別對應其子元素所在的軌道。stretch跟其他不太一樣,它會將元素從所在軌道的頭拉伸到尾。

align-items 和 justify-content

[align-items 和 justify-content]

例子中我們要將內容水平和垂直居中,可以通過在容器上設置下面這些屬性:

.center-content {
    display: grid;
    align-items: center;
    justify-content: center;
}

示例地址

使用舊的網格布局實現兩欄布局

如果使用舊的網格布局方式創建,我們需要考慮實現中的諸多限制。舊的布局方式不僅沒有grid-gap,而且你需要在每一個網格元素上聲明網格元素的起始位置,否則默認會設置為1,這樣所有的網格都會堆在第一列。

舊版本的布局方式需要通過增加間距作為網格軌道的一部分,也需要設置每個網格從哪里開始:

.grid-legacy {
   display: -ms-grid;
   -ms-grid-columns: 1fr 1rem 1fr; // 取代 gap 間距
}
.grid-legacy:first-child {
   -ms-grid-column: 1;
}
.grid-legacy:last-child {
    -ms-grid-column: 3;
}

舊的布局方式實現對齊和全高度

舊的布局方式跟IE 11中Flexbox有一樣的問題,在容器上設置最小高度(min-height)不一定會生效。這個問題通過網格布局來解決更方便。

為了實現這個效果我們在父容器的行屬性上使用minmax方法,minmax指定了行或列的最大和最小值。

-ms-grid-rows: minmax(100vh, 1fr);

在子元素上我們聲明一個單位為1fr的單列單行的網格:

.ms-cell {
   -ms-grid-columns: 1fr;
   -ms-grid-rows: 1fr;
}

最后,因為我們不能像Flexbox或最新網格布局那樣根據父元素對齊,我們必須使用元素自身的對齊方式來對齊:

.ms-align-center {
    -ms-grid-column: 1;
    -ms-grid-column-align: center; // 新型grid布局中的 align-self
    -ms-grid-row-align: center; // 新型grid布局中的 justify-self
}

舊的兩列布局示例

到此我們實現了如何創建列、實現間距、內容對齊及對舊的網格布局的支持。接下來讓我們實驗下如何通過grid實現內邊距。

通過CSS網格實現內邊距(Negative Space)

網格布局允許你通過grid-column-start屬性指定列開始的位置,所以就有了可以在網格內創建內邊距的可能性。

使用grid-template-columns和grid-column-start創建內邊距

[使用grid-template-columns和grid-column-start創建內邊距]

創建內邊距的一種方式是在列的實際位置上設置一個數字,空出網格元素的原始空間, 網格元素也會被push到新的網格列。

grid-column-start push

[隨著grid-column-start push 第一項]

在上面的內邊距示例中,html結構中用一個div包裹另外一個div:

<div class="grid">
    <div class="child"><!-- 內容 --></div>
</div

網格像這樣設置:

.grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
}

為了讓子元素從右側開始,我們設置子元素從第2列開始:

.child {
    grid-column-start: 2;
}

注意:在Firefox 52中的一個差異導致一個垂直對齊問題——基于FR單位的行不會拉伸得跟整個窗口一樣高。為了解決(address)這個問題我們設置子元素為網格項,并給每一行設置一個想要的高度:

.l-grid--full-height {
    grid-template-rows: minmax(100vh, 1fr);
}

設置內邊距示例

用內容死區(content dead-zones)創建空白

在四列布局中,給本來在第三列的網格項上設置grid-column-start:2;,那么會找到下一個可用的第二列來填充空間。

網格軌道會跳過某些列,直到找到下一列。我們可以利用這個方法在網格內創建空白,沒有內容的網格也會被分配。
[創建空白示例]


[使用grid-template-columns 和 grid-column-start創建空白]

創建行

如果我們想分割布局為四份,我們目前所了解的關于列的布局方式對行同樣有效:

.grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 250px 250px;
}

[同時使用grid-template-columns 和 grid-template-rows創建網格布局]

理想情況下這個示例是沒問題的。因為此時每個網格項的內容足夠少而不會撐開每行。但隨著內容的變化,一切都不一樣了。當示例中的內容超出指定行的大小后,看下會發生什么:


[內容超出聲明的行高]

我們創建了250px高的兩行,如果內容超過每行的高度,將會打破布局并和后面的行的內容重疊。并不是一個我們想要的結果。

靈活的設置最小值

我們在該場景下需要的是設置最小尺寸的能力,但又要允許尺寸可以根據內容彈性變化。這里我們通過上面舊瀏覽器示例中的minmax關鍵字實現。

.grid {
    grid-template-rows: minmax(250px, auto) minmax(250px, auto);
}

創建有最小值的彈性行

現在我們已經了解了創建帶有內容的行的基礎方法,我們開始來創建水平和垂直交錯的更復雜網格布局。


[使用grid-column-start和span關鍵字創建復雜網格布局Unsplash]

創建更復雜的網格

我們開始創建更復雜的網格布局。將網格中的每個網格項設置成占據多條軌道,在一列內,我們能通過grid-column-startgrid-column-end實現,或者通過如下所示更簡單的寫法:

grid-column: 1 / 3;

用這種實現方式的弊端是難以“模塊化”,為了定位每塊內容需要寫很多代碼。span關鍵字更符合模塊化的思路,因為我們能放在任何地方,讓網格來控制他。我們可以定義網格項的開始位置,及其占據的軌道數:

.span-column-3 {
    grid-column-start: span 3;
}

任何添加該class的網格將會從其開始位置,占據三個軌道。

[通過span實現的復雜網格]

使用span設計一個布局

我們能設計一個多軌道布局,通過將布局分解為grid布局中的最小單元。本示例中的最小單位是圖中高亮的部分。


[通過最小網格單位結合span創建更大的網格]

圍繞最小單位,我們能靈活的使用span來創建一些有意思的布局,因為span是可以疊加的——你可以結合列和行的軌道在網格中創建多層級。

不需要媒體查詢(media queries)的彈性網格

雖然上面說到的例子能在可用空間內適應變化,但是沒有一個是專門為空間變化設計的。網格有兩個非常有用的特性來適應可用空間的變化。這兩個屬性叫‘auto-fit’和‘auto-fill’,像下面這樣結合repeat functionminmax function使用:

grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

這些值代替了repeat中的數字,并計算在每條軌道上會填充多少行或列。二者之間最大不同是當一條軌道上空白的溢出時的他們的處理方式不同。

auto-fit嘗試在不導致列溢出的情況下,放置該列能處理的最大數量的重復元素。當沒有足夠的空間來放置更多的元素時,之后的元素將會放到下一行,不能填滿的空間將會被保留。

auto-fill

[示例:auto-fill. auto-fill會保留后面空間,反之auto-fit會讓空白收縮為0px]

auto-fill的表現跟auto-fit類似,但是任何的空白空間都會自動收縮,同時這一行的元素也會被拉升——類似flexbox的效果,列會隨著可用空間變小發生折疊。

grid-auto-fit示例

[grid-auto-fit示例]

依賴媒體查詢的布局跟窗口大小關系很大,這不夠模塊化——系統內的組件應該能根據可用空間自適應。那么在實踐中會是什么樣的呢?

auto-fit

[grid auto-fit的真實示例]

[網格auto-fit示例]

這只是冰山一角

我們已經經歷了快十五年的CSS浮動為主的布局方式,我們上面學習了幾乎所有你能用float實現的布局——CSS網格布局是這個領域的新代表,仍然還有許多東西需要去嘗試和學習。

現在最重要的步驟是開始使用它。在構建、創建更多高級布局的時候會很方便。網格布局還有不少未知領域,一旦我們更好地理解其能力并開始與其他特性結合,我們便能用更少代碼創造更多有趣、靈活的布局,并能減少些框架抽象的麻煩。

如果你感興趣并想進一步探究CSS網格,可以試下Rachel Andrew的例子,這里面通過帶解釋說明的實例探討了CSS網格布局的每一個特性。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容

  • 簡介 CSS Grid布局 (又名"網格"),是一個基于二維網格布局的系統,旨在改變我們基于網格設計的用戶界面方式...
    咕咚咚bells閱讀 2,530評論 0 4
  • 簡介CSS網格布局(又稱“網格”),是一種二維網格布局系統。CSS在處理網頁布局方面一直做的不是很好。一開始我們用...
    _leonlee閱讀 65,113評論 25 173
  • 前言 溫馨提示:本文較長,圖片較多,本來是想寫一篇 CSS 布局方式的,但是奈何 CSS 布局方式種類太多并且實現...
    sunshine小小倩閱讀 3,152評論 0 59
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,774評論 1 92
  • 第十四章 這一夜,二人從天界仙境,聊道凡塵人事,未曾刻意回避什么,不經意提到,聊一聊,話題自個兒就偏到十萬八千里之...
    若莎Elsa閱讀 7,518評論 1 52