網格佈局 ——(語法篇)

這是HTML&CSS重點知識點合集第四篇,內容稍微有點多。其他文章見文末。css

1、網格佈局(Grid)

前面咱們講了 伸縮盒。咱們講到,伸縮盒是傳統盒模型佈局的一種代替,而且伸縮容器以及flex item的屬性足以應付咱們經常使用的各類佈局模式,那爲何還會出現Grid網格佈局呢?html

可能你已經知道了,以往任何佈局方式幾乎都是一維佈局,而Grid最大的特點就是採用了二維佈局。固然,Grid的出現並非用來替代flex-layout,而是對它的補充。前者擅長一維然後者擅長二維,它們須要各司其職。前端

2、瀏覽器兼容

咱們來看看它的兼容性吧。從2017年3月份開始,Grid開始獲得部分的瀏覽器的支持。css3

gridBrowserSupport

3、Grid和table

你可能會有疑問,Grid不就是設置行和列嘛?但是這些table不是均可以作嘛?那爲啥還要有Grid?git

從效果上來看,Grid佈局和table同樣都是把一部分區域經過行和列來劃分紅一小塊一小塊方格。可是實際上它們是有很大區別的: 1.首先,它們的本質區別在於Grid是用純CSS實現的佈局方式。而table佈局依賴HTML標籤,它有固定的結構。Grid能夠直接使用 grid-template-columnsgrid-template-rows 屬性來設置容器的行和列的長度。例如:github

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px;
  grid-template-rows: 50px 50px 50px;
}
複製代碼

當咱們對一個容器設置上述樣式,就會生成一個三行三列且每一小格長寬均爲50px。點擊這裏 本身實踐一下!瀏覽器

grid exp

2.其次,基於table固定標籤的結構,它的佈局就很不自由。可是Grid不一樣,使用它來對二維佈局能夠利用幾行代碼輕鬆實現,靈活性很高。網絡

4、Grid佈局語法

在具體講Grid佈局以前,咱們先來認識幾個術語。ide

第1、和伸縮盒同樣,網格佈局中也有容器這個概念。網格容器(Grid container),爲其內容創建新的網格格式化上下文,容器外元素和容器內元素互不干擾。好比上圖中盛裝數字塊的最外容器。函數

第2、網格線(Grid line),顧名思義,容器的水平垂直分割線。它構建出網格軌道、網格單元和網格區域。網格線是有數字索引的,能夠自定義名稱。

第3、網格軌道(Grid track),網格內容塊之間水平或垂直的空間。

第4、網格單元格(Grid cell),網格內容的單元區塊,是能夠放置內容的最小區塊。好比上圖中的某一個數字塊。

第5、網格區域(Grid area),以網格線爲界劃定區域。

(1). 網格容器

網格容器全部的屬性:

  1. display
  2. grid-template-columns
  3. grid-template-rows
  4. grid-template-areas
  5. grid-template
  6. grid-column-gap
  7. grid-row-gap
  8. grid-gap
  9. justify-items
  10. align-items
  11. place-items
  12. justify-content
  13. align-content
  14. place-content
  15. grid-auto-columns
  16. grid-auto-rows
  17. grid-auto-flow
  18. grid

和伸縮盒不同,在網格佈局是一個二維佈局,有着行和列的概念,因此咱們接下來說的容器屬性是:如何定義網格容器以及如何定義網格的行數、列數以及網格的大小(長寬)。

1. display

.container {
  display: grid | inline-grid;
}
複製代碼

2. grid-template-columnsgrid-template-rows

就如上面例子中同樣,它們用來定義網格的行數、列數、網格大小。假設咱們須要定義一個四行四列的容器能夠這樣寫:grid-template-columns: 50px 50px 50px 50px; grid-template-rows: 50px 50px 50px 50px;

固然,屬性值除了可使用 px 做爲單位還可使用 em% 來做爲單位。在CSS3規範中,咱們看到這樣一段話:

A flexible length or is a dimension with the fr unit, which represents a fraction of the leftover space in the grid container. Tracks sized with fr units are called flexible tracks as they flex in response to leftover space similar to how flex items fill space in a flex container.

翻譯過來就是說 fr 這個單位表示的是網格容器中剩餘空間的一部分。大小爲 fr 單位的‘軌道’稱爲彈性‘軌道’,它們會響應式的填充剩餘的內容,和伸縮盒中的flex item會自動填充剩餘空間很類似。

假設設置一個三行四列的列表,但願最後一列自適應容器寬度就能夠這樣設置:

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 1fr;
  grid-template-rows: 50px 50px 50px;
}
複製代碼

三行四列,最後一列自適

那若是但願第一列長度固定然後三列中第一列佔剩餘長度的四分之一,第二列佔二分之一最後一列佔四分之一應該該怎麼寫呢?

.container {
  display: grid;
  grid-template-columns: 50px 1fr 2fr 1fr;
  grid-template-rows: 50px 50px 50px;
}
複製代碼

fr用作分數

怎麼樣?神奇吧?

對於這兩個屬性,CSS3還提供了一個函數:repeat()。它的做用相信你一看就知道了:

.container {
  display: grid;
  grid-template-columns: 50px 1fr 2fr 1fr;
  grid-template-rows: repeat(3, 50px);
}
複製代碼

3. grid-template-areas

.container {
  grid-template-areas: "<grid-area-name> | . | none | ..." "...";
}
複製代碼

它用來定義網格區域,使用 grid-area 調用聲明好的網格區域名稱用來放置對應的網格項目。

舉個栗子:

.item-a {
  grid-area: header;
}
.item-b {
  grid-area: main;
}
.item-c {
  grid-area: sidebar;
}
.item-d {
  grid-area: footer;
}

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas: 
    "header header header header"
    "main main . sidebar"
    "footer footer footer footer";
}
複製代碼

咱們經過Grid item的屬性 grid-area(後面會講到)來爲item設置相應的名稱,而後再利用容器屬性 grid-template-areas經過設置的名稱對整個容器佈局。下面就是佈局的效果:

grid-area

4. grid-template

這是屬性 grid-template-rowsgrid-template-columnsgrid-template-areas 三個屬性的簡寫。

.container {
  grid-template: none | <grid-template-rows> / <grid-template-columns>;
}
複製代碼

當僅僅設置 grid-template-rowsgrid-template-columns 時,grid-template-areas 自動爲 none。中間使用符號 / 隔開。好比前面一個例子就能夠寫成這樣:

.container {
  display: grid;
  grid-template: repeat(3, 50px) / 50px 1fr 2fr 1fr;
}
複製代碼

grid-template 不會隱式的設置 grid-auto-columnsgrid-auto-rowsgrid-auto-flow,因此推薦使用 grid 屬性來代替。

5. grid-row-gapgrid-column-gap

定義網格之間的間距(不包括grid item到容器邊緣的間距)

6. justify-items

.container {
  justify-items: start | end | center | stretch; /* 默認值爲stretch */
}
複製代碼

定義Grid item的內容在水平方向上的對齊方式(其值指的是在單元格內的表現)。好比:

.container {
  justify-items: start;
}
複製代碼

justify-items-start

.container {
  justify-items: center;
}
複製代碼

justify-items-center

和伸縮容器的 align-items 同樣,它也能在子項目中使用屬性 justify-self 進行覆蓋。

7. align-items

.container {
  align-items: start | end | center | stretch; 
}
複製代碼

justify-items 差很少,只不過這個屬性做用的是另外一個軸方向。

.container {
  align-items: start;
}
複製代碼

align-items-start

一樣的,這個屬性值也能夠利用子項目的屬性 align-self 進行覆蓋。

8. place-items
是屬性 align-items 和屬性 justify-items 的簡寫。中間使用 / 進行分隔。若只有一個值,那麼將同時設置兩個相同的值。

注:除了Edge,全部主流瀏覽器均支持該屬性。

9. justify-content
有些時候,當咱們對單元格的長設置了固定值,這時就有可能致使全部網格的長加起來不能撐滿整個網格容器。好比下面這樣:

justify-content-start

因此,justify-content 屬性就運用而生。它主要就是設置容器中內容的排布方式的。

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

栗子以下:

.container {
  justify-content: space-around;
}
複製代碼

justify content space-around

10. align-content
和上一個屬性相呼應,若是咱們對每一個單元格的高設置固定值,這是就有可能致使全部單元格的高加起來沒有填滿整個容器。

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

align-content-start

11. place-content
前兩個屬性的簡寫形式,若是隻設置一個值,則表示設置相同的值。

除Edge外,全部主流瀏覽器都支持這個屬性。

12. grid-auto-columnsgrid-auto-rows
設置隱式網格軌道的大小。

.container {
  grid-auto-columns: <track-size> ...;
  grid-auto-rows: <track-size> ...;
  /* <track-size> 長度,能夠是前面提到的任何表示形式 */
}
複製代碼

其實這個屬性就是設置以後有可能動態添加進來的item的長度和高度。來看下面一個栗子: 首先,咱們設置好高寬:

.container {
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px;
}
複製代碼

設置高寬高寬

如今咱們來對Grid item設置一下它的位置(這兩個屬性接下來會講到,用來設置item的位置,其中/兩側的值分別是網格軌道的起始位置和終點位置):

.item-a {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}
複製代碼

設置item位置

在這裏咱們設置了一個 item-b,而且容易看出,它在原先定義的網格中並不存在,因而就有了上圖。看到,第3、四列的長度爲0,且 item-b的這一列的長度也爲沒設置(默認值爲 auto,和前面已經定義的長度同樣)。

如何解決第3、四列的長度問題呢?這裏咱們就能夠利用屬性 grid-auto-columns 來動態的設置後添加進來item的長度。

.container {
  grid-auto-columns: 60px;
}
複製代碼

自動設置長度

13. grid-auto-flow

.container {
  grid-auto-flow: row | column | row dense | column dense;
}
複製代碼

它定義了默認「流」方向,它的動做和flexbox裏的 flex-direction 有些類似。

14. grid
它是屬性 grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rowsgrid-auto-columns 以及grid-auto-flow 的縮寫。

.container {
  grid: none | <grid-template> | <grid-template-rows> / [auto-flow && dense?] <grid-auto-columns>? | [auto-flow && dense?] <grid-auto-rows>? / <grid-template-columns>;
}
複製代碼

舉個栗子就明白啦:

.container {
  grid: 100px 300px / 3fr 1fr;
}

/* 等同於下面: */
.container {
  grid-template-rows: 100px 300px;
  grid-template-columns: 3fr 1fr;
}
複製代碼

再好比:

.container {
  grid: auto-flow / 200px 1fr;
}

/* 等同於下面: */
.container {
  grid-auto-flow: row;
  grid-template-columns: 200px 1fr;
}

.container {
  grid: auto-flow dense 100px / 1fr 2fr;
}

/* 等同於 */
.container {
  grid-auto-flow: row dense;
  grid-auto-rows: 100px;
  grid-template-columns: 1fr 2fr;
}
複製代碼

(2). 網格項目

全部Grid item屬性:

  1. grid-column-start
  2. grid-column-end
  3. grid-row-start
  4. grid-row-end
  5. grid-column
  6. grid-row
  7. grid-area
  8. justify-self
  9. align-self
  10. place-self

1. grid-column-startgrid-column-endgrid-row-startgrid-row-end
這四個屬性是用來定義item的四周位置的。

.item {
  grid-column-start: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-column-end: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-row-start: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-row-end: <line> | <number> | <name> | span <number> | span <name> | auto;
}
複製代碼

其中 <line> 的值能夠是一個數字,表示第幾根網格線,也能夠是已經定義過的網格線名稱。

舉個栗子:

.item-a {
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start;
  grid-row-end: 3;
}
複製代碼

grid-columns-start | grid-row-start1

再好比:

.item-b {
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2;
  grid-row-end: span 2;
}
複製代碼

grid-columns-start | grid-row-start2

grid-column-end 或者 grid-row-end 沒有被設置,則默認的跨越步長爲1。Grid item有時候可能會相互重疊,這時候可使用 z-index 控制其層疊順序。

2. grid-columngrid-row
前者是屬性 grid-column-startgrid-column-end 的簡寫,後者是屬性 grid-row-startgrid-row-end 的簡寫。

.item {
  grid-column: <start-line> / <end-line> | <start-line> / span <value>;
  grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
複製代碼

例如:

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}
複製代碼

grid-column grid-row

3. grid-area
這個屬性咱們前面提到過,它能夠用來定義Grid item的名稱,用來給屬性 grid-template-areas 設置佈局。固然,它也能夠看成屬性 grid-row-startgrid-column-startgrid-row-endgrid-column-end 的簡寫。

.item {
  grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
複製代碼

關於 <name> 的栗子上面已經有了,這裏再也不贅述。下面舉第二個值得栗子:

.item-d {
  grid-area: 1 / col4-start / last-line / 6;
}
複製代碼

grid-area

4. justify-selfalign-self
前面也提到啦,這兩個屬性都是子元素對父元素設置的 justify-itemsalign-items 進行覆蓋。這裏就再也不舉栗子惹~

5. place-self
這個屬性仍是比較厲(sao)害(qi)的~ 看用法:

.item-a {
  place-self: auto | <align-self> / <justify-self>;
}
複製代碼

栗子:

.item-a {
  place-self: center;
}
複製代碼

place-self center

.item-a {
  place-self: center stretch;
}
複製代碼

place-self center stretch

最後,Grid item對屬性 floatdisplay: inline-blockdisplay: table-cellvertical-aligncolumn-* 失效。

(3). 網格佈局帶來的函數和關鍵字

  • 當咱們設置長度時,咱們可使用像 px、res 、%,這些咱們以往使用的單位。咱們還可使用關鍵字:min-contentmax-contentauto,固然,可能最有用的仍是 fr
  • 咱們也能夠經過函數 minmax() 來設置一個大小的區間段。
  • repeat(),前面已經有講過,這裏再也不贅述。

5、網格佈局中的動畫

根據CSS網格佈局模型Level 1,有5個網格動畫屬性,分別是: grid-gapgrid-row-gapgrid-column-gapgrid-template-columnsgrid-template-rows

我看能夠利用 @keyframes 規則,經過改變這五個屬性大小達到想要的動畫效果。

這裏有個使用屬性 transition 來實現動畫的栗子:動畫demo

6、伸縮盒佈局和網格佈局帶來的思考

(1). 爲何網格佈局容器中有屬性 justify-items 而伸縮容器沒有屬性 justify-items

首先,咱們來對比一下伸縮容器的 justify-content 和網格容器的 justify-content:

flexbox justify-content space-around

Grid justify-content space-around

容易看出,在伸縮容器中,每個item都是一個排列單元,而在網格容器中,每一列是一個排列單元。

如今咱們再來看看網格容器的屬性:justify-items

Grid justify-items start

它的做用是在水平方向設置item內容的對齊方式。若是設置爲 start,則表示全部item的內容靠近左網格線。若是設置爲 center,則表示將內容在水平方向居中顯示。在網格這個二維空間中,顯然它是很是有用的屬性。而若是咱們也爲伸縮佈局設置這個屬性,很顯然和它的屬性 justify-content 的做用發生的重疊,且效果沒有前者好。所以,在伸縮容器中定義 justify-items 是沒有必要的。

(2). 爲何最好不要使用flex佈局做爲整個頁面的佈局?

當咱們有大量的內容繪製到頁面上、或者內容更改的,在2g或者網絡加載不穩定的時候,頁面是不穩定的。網格佈局會以流的形式被獲取到,且能使咱們在頁面所有加載出來以前就看到內容,而flex佈局因爲其相對佈局的特徵會致使佈局的重排。

固然並非說網格佈局就必定不會引起重排,它是有前提的:網格的劃分是預先肯定的,好比根據視窗高度來肯定。

假如內容是根據內容彈性改變的,那麼也沒法避免發生重排。

ps: 最後的最後,終於整理完啦,滿滿的收穫呀。固然啦,但願你能有所收穫~
這裏給你們推薦一個有趣的Grid遊戲吧:grid garden,還蠻有意思的,用來入門簡直不要太好~


這是HTML&CSS重點知識點合集的其中一篇,合集其它文章:
1.語義化HTML的重要性
2.傳說中的BFC
3.CSS佈局神器——伸縮盒(語法篇)


參考文章:
1.將來佈局之星Grid-2017-09-24 by 考拉海購前端團隊
2.CSS Grid 網格佈局教程-2019-03-25 by 阮一峯

推薦閱讀: 1.A Complete Gide to Grid-2019-9-13 by Chris

有問題?發送 issues 給我~

相關文章
相關標籤/搜索