css網格佈局:建立網格容器

原文做者:Rachel Andrew
原文連接:www.smashingmagazine.com/2020/01/und…css

譯者注: CSS Grid佈局 (又名"網格"),是一個基於二維網格佈局的系統,旨在改變咱們基於網格設計的用戶界面方式。咱們經常使用的Flex 佈局是軸線佈局,只能指定"項目"針對軸線的位置,能夠看做是一維佈局,並不適用於複雜的二維佈局。網格(Grid)是第一個專門爲解決佈局問題而建立的CSS模塊,用來解決咱們以前在製做網站時使用各類複雜處理的佈局問題。html

在進入正文以前爲了防止翻譯上存在一些歧義或者不許確的地方,你們先了解幾個關於網格佈局的關鍵術語。前端

  • container:容器,就是採用網格佈局的區域
  • row line: 行線,容器裏面的水平區域稱爲"行"(row)
  • column line: 列線,垂直區域稱爲"列"
  • track: 網格軌道,是兩條網格線之間的空間,即行線和行線,或列線和列線之間所造成的區域,用來擺放子元素
  • gap: 網格間距,行線和行線,或列線和列線之間所造成的不可利用的區域,用來分隔元素
  • cell: 網格單元格,由行線和列線所分隔出來的區域,用來擺放子元素
  • area: 網格區域,由單個或多個網格單元格組成,用來擺放子元素
  • grid line: 網格線,劃分網格的線,水平網格線劃分出行,垂直網格線劃分出列

好了,下面正式開始:

概要:在一個新的系列中,Rachel Andrew將會向咱們介紹css網格的規範。在本次文章中,咱們將會詳細瞭解當咱們建立了一個網格容器的時候會發生什麼,以及各類各樣能夠應用在網格容器上的屬性。瀏覽器

這是Smashing Magazine上面關於網格佈局系列文章的開篇。儘管網格佈局在2017年瀏覽器就已經支持使用了,可是不少開發者仍是沒有機會在項目中使用它。彷佛有不少新的屬性和值與CSS網格佈局相關。這使得它勢不可擋。然而,它的不少規範細節均可以使用不一樣的方式來實現,這意味着你在沒有徹底瞭解規範的狀況下,也能夠開始使用。本系列旨在將您從網格佈局的新手帶到專家:一路上有不少實用的使用技巧交給你們。ide

開篇的文章將會包括:你在建立一個網格容器時將會發生什麼,以及各類你能夠應用在父元素上的屬性以控制網格。您將發現,有幾個用例僅在將屬性應用在網格容器上時纔會生效。 這篇文章中,咱們包括:svg

  • 使用display: grid或者display: inline-grid建立網格容器
  • 使用grid-template-columns 和 grid-template-rows屬性設置列和行
  • 使用grid-auto-columns 和 grid-auto-rows控制內含尺寸

建立一個網格容器

grid就像flex佈局同樣,是一種display屬性。因此使用display: grid來告訴瀏覽器你想使用網格佈局。以後,設置了網格屬性的元素將成爲一個塊級元素,它裏面全部的直接子元素都將處於一個網格格式上下文中。這就代表,它們都將表現出網格元素的性質,而不是普通的塊級或者行內元素。函數

也許,你尚未在你的頁面上看到差異。那是由於你尚未建立一個行或者列。儘管已經默認建立了一個行,幷包含你全部的子元素。這些子元素在一列中上下排布。表現出的行爲看起來就像塊級元素。佈局

若是有任何文本字符串(未包裝在元素中)便是網格容器的直接子級,你就會看到不一樣,由於字符串將包裝在匿名元素中併成爲網格項。任何行內元素,好比span,只要直接處於網格容器中,就會表現出網格項的屬性。flex

下面的示例有兩個塊級元素,在字符串中添加一個包含在span中的文字字符串。咱們最終獲得5個網格項:網站

  • 兩個div元素
  • span前面的文本字符串
  • span
  • span以後的文本字符串
// html
<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
This string of text follows the grid.
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

最後的表現:

若是使用Firefox的grid Inspector檢查網格,能夠看到爲爲每一個網格項建立的5行軌跡。

Grid Inspector能夠幫助你查看建立了多少row元素
你也能夠經過display: inline-grid建立一個行內網格。在這個例子中,你的網格變成了一個行級盒子。可是,直接子項仍然是網格項,其行爲方式與塊級框中的網格項相同(它只是外部顯示類型)。這就是爲何當網格容器與頁面上的其餘框並排時,它的行爲與上面的相同。

下一個示例有一個網格,後面跟着一個文本字符串,由於這是一個內聯級別的網格,文本能夠與它一塊兒顯示。內聯級別的內容不會像塊級別的內容那樣拉伸以佔用內聯維度中的全部空間。

<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
This string of text follows the grid.
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: inline-grid;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

最後的表現:

列和行

爲了使佈局看起來像網格,你須要添加行和列。咱們使用grid-template-columns 和 grid-template-rows屬性來建立。在規範中有一個定義叫作網格軌道track-list

這些屬性指定了行的名字以及網格的追蹤尺寸函數。網格模板列屬性grid-template-columns指定網格列的尺寸跟蹤方法,而網格模板行grid-template-rows指定網格行的跟蹤函數。

下面列出了一部分有效影響軌道尺寸的值:

屬性 做用
grid-template-columns: 100px 100px 200px; 建立三列網格:第一列是100px,第二列是100px,第三列是200px
grid-template-columns: min-content max-content fit-content(10em) 建立三列網格:第一列追蹤min-content尺寸,第二列是max-content,若是容器大小超過10em,第三列也是max-content,不然就撐到10em
grid-template-columns: 1fr 1fr 1fr; 使用fr建立了三列網格,這三列將平分容器尺寸
grid-template-columns: repeat(2, 10em 1fr); 使用重複命令建立了尺寸分別爲10em 1fr 10em 1fr 的四列網格
grid-template-columns: repeat(auto-fill, 200px); 建立儘量多的寬爲200px的列,若是剩餘控件不足200px,就留下空白
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); 建立儘量多的寬爲200px的列,若是剩餘控件不足200px,已建立的列將平均分配剩餘空間。
grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end]; 建立三列網格:第一列和第三列各有一份可用空間,而中間列佔三份。將行名稱放在方括號中對行進行命名。

如您所見,有不少方法能夠建立網格軌道(track list)!讓咱們來看看這些都是如何工做的,並給出一些提示,說明爲何要使用每這些屬性。

使用長度單位

你可使用任何長度單位或者百分比建立你的網格軌道(tracks)。若是網格軌道(tracks)的大小加起來小於網格容器中可用的大小,則默認狀況下,網格軌道(tracks)將會從左到右排列,剩餘部分就會空白。這是由於align-content 和 justify-content這兩個屬性的默認值是start。你可使用校準元素將元素分隔開或者移動到容器最後面。詳細的介紹能夠看個人這篇文章「How To Align Things In CSS」.

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 100px 200px 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

你也可使用min-content, max-content 和 fit-content()屬性。使用min-content屬性,會建立儘量小的網格軌道(tracks)來避免出現溢出的狀況。因此,看成爲列的屬性時,會盡量的摺疊裏面的內容。這時網格軌道(track)的高度就變成了容器中最長單詞或最大固定大小元素的大小。

使用max-content屬性不會引發任何折行。在一列中,文本字符不會折行,這可能會引發溢出。

fit-content是css函數,只能經過傳值來使用。這個值就是網格軌道所能增加到的最大值。它的表現就像max-content同樣,會隨着內容的不斷變長而變寬。可是當內容長度超過這個值之後,裏面的元素就開始折行。因此,這個網格軌道有可能小於你所傳的值,但不會比它大。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>Item Three Item Three Item Three</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: min-content max-content fit-content(10em);
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果

你能夠在個人這篇文章 How Big Is That Box? Understanding Sizing In CSS Layout中發現更多關於網格尺寸和佈局的方法。

若是你的tracks佔用的空間超過你的容器,它們就會溢出。若是你使用百分比,就與基於百分比的浮動或彈性佈局同樣,若是想要避免溢出,就要注意總和不要超過100%。

fr 單位

網格佈局包括一種方法可讓你避免本身計算百分比-就是使用fr。它並非一個值,因此不能和calc()一塊兒使用。它是一個彈性單位,表示網格中的可用空間。

這就表示,當咱們1fr 1fr 1fr;設置時,剩餘空間會被分紅三分並平分空間。當使用2fr 1fr 1fr,空間會被分紅四分,其中兩份被分配給第一個網格軌道,剩下兩個網格軌道分別佔據一份。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>Item Three Item Three Item Three</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

最終渲染:

須要注意的是,默認狀況下共享的是可用空間,而不是容器中的總空間。若是你的任意一個網格軌道中包含規定尺寸的元素或者一個沒法被折行的文本,它會在空間被分配以前佈局。
在一下個例子中,我將去掉第三列中字符的字間距。這樣就造成了一個長的不可折斷的字符串,因此,在進行網格佈局以前會優先處理字符串的佈局,將它所在的列撐開了。而後剩餘的兩列按照2:1的比例進行佈局。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>ItemThreeItemThreeItemThree</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

你能夠將固定尺寸的網格軌道和fr一塊兒使用。例如你能夠建立一個容器,包含兩個固定尺寸的列,兩個列中間區域自適應。

<div class="grid">
  <div>Fixed</div>
  <div>Flexible</div>
  <div>Fixed</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 100px 1fr 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

另外,你也可使用fit-content(300px)建立第一列,剩餘得部分用fr處理。這樣容器的第一部分就會根據內容佔據所須要的空間。fr單位的列會擴大佔據剩餘部分。 若是元素中的內容放入更大的內容(好比設置屬性max-width: 100%的圖片),第一列最大寬度只能到300px。fr單位的列佔據剩餘部分。 將fr和fit-content一塊兒使用也是讓你的網站更加靈活的一種方式。

<div class="grid">
  <div><svg width="24" height="24" viewBox="0 0 24 24">
  <path d="M23,12L20.56,9.22L20.9,5.54L17.29,4.72L15.4,1.54L12,3L8.6,1.54L6.71,4.72L3.1,5.53L3.44,9.21L1,12L3.44,14.78L3.1,18.47L6.71,19.29L8.6,22.47L12,21L15.4,22.46L17.29,19.28L20.9,18.46L20.56,14.78L23,12M13,17H11V15H13V17M13,13H11V7H13V13Z"></path>
</svg></div>
  <div>This side is flexible</div>
</div>

<div class="grid">
  <div><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/balloon-sq4.jpg" alt="balloons"></div>
  <div>This side is flexible</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  margin: 1em 0;
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: fit-content(300px) 1fr;
  width: 600px;
}

img {
  max-width: 100%;
  display: block;
}

複製代碼

渲染結果:

REPEAT()方法

使用repeat()函數建立網格軌道能夠很方便的建立重複屬性的列,避免一遍又一遍的輸入一樣的值。好比,下面兩列的做用是同樣的。

grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(12, 1fr);
複製代碼

repeat()函數的第一個參數是要建立的網格軌道個數,第二個參數爲列的尺寸,用逗號隔開。

你也能夠將repeat()做爲一部分參數,下面的例子中,建立了一個1fr的列,三個寬爲200px的列,最後一列爲1fr。

grid-template-columns: 1fr repeat(3,200px) 1fr
複製代碼

另外,函數傳入一個值表示建立列的個數,但也可使用auto-fill or auto-fit。使用這兩個關鍵詞意味着建立列的個數並非固定的,而是根據容器的寬度,建立儘量多的列。

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, 200px);
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

若是建立列的寬度是固定的,那麼除非容器正好能被列進行平分,不然就會留下空白部分。好比個人容器寬度爲500px,就會建立兩個200px的列和100px的空白。

針對上面的問題,可使用另一個網格函數定義最小值,剩餘的空間能夠被全部已建立的列進行平分。minmax()定義最小值和最大值。好比定義列最小爲200px,最大爲1 fr,那麼就會建立儘量多的寬爲200px的列來填充容器。由於最大值爲1fr,因此若是有剩餘空間,就會被已建立列平分。

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

上面,我提到了兩個關鍵詞auto-fill and auto-fit。若是第一行有足夠的內容去填充,那麼他們的表現是同樣的。可是若是沒有(好比刪除其它內容只剩下一列),那麼它們的表現就會有所不一樣。

使用auto-fill會保留剩餘空間,儘管沒有內容填充了。

<div class="grid">
  <div>Item One</div>

</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

可是auto-fit會將剩餘空間摺疊。

<div class="grid">
  <div>Item One</div>

</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
複製代碼

渲染結果:

經過Firefox Grid Inspector,能夠看到,第二列仍然存在,只不過寬度變爲了0。咱們能夠看到第三條網格線,這說明容器中存在兩條網格軌道。

命名行

我最後說一下行的命名。當使用網格的時候,你能夠得到每行行數,如今你也能夠給每一行命名。將行的名字放在中括號裏。也能夠爲行定義多個名稱,用空格分開。下面的例子中,每一個行我都定義了兩個名字。

grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]
複製代碼

除了單詞span,你能夠爲行定義任何您喜歡的名稱,由於span是一個保留字,在網格上放置項目時使用它。
注意:本系列後續文章中,我將更多地討論基於行的佈局以及如何使用命名行。同時,個人這篇文章「Naming Things in CSS Grid Layout」以幫助你更好的理解這些。

顯式vs隱式網格

當使用grid-template-columns 和 grid-template-rows屬性定義時,你就是很明確的顯式定義了網格。每個網格軌跡都是根據你的賦值建立的。
當你定義的軌道數量超過容器的空間,或者將一個單元放在建立的網格以外,將建立隱式網格軌道。這些隱式軌道默認自適應大小。好比,我在父元素上聲明display:grid,它包含的每一項都會建立一個行軌道。儘管我並無去定義row,可是由於它們變成了網格佈局中的元素,爲了放置這些元素,就會自動建立出行軌道。

你可使用grid-auto-rows 或者 grid-auto-columns屬性設置隱式行或者列的尺寸。若是你但願全部的隱式列都至少有200px的寬,並隨着內容的增大而增大,你能夠這樣設置:

grid-auto-rows: minmax(200px, auto)
複製代碼

若是你但願第一個隱式行自適應大小,第二行爲min-content直到全部網格項都被容納。你能夠傳多個值:

grid-auto-rows: auto 100px
複製代碼
<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
複製代碼
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-auto-rows: auto 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}

複製代碼

使用具備自動放置功能的網格

建立一個網格(並容許瀏覽器自動放置元素)可讓您實現很是有價值的模式方面有很長的路要走。咱們尚未設計在網格上放置項目,可是許多狀況下網格的佈局不須要進行任何放置。容器的子元素只是簡單地按照代碼中的順序自動放置在每個網格中。

若是你剛剛接觸css網格,那麼嘗試使用不一樣方式定義網格軌跡並查看元素是如何放置的,是一個很好的開始。

END

若是你們想要持續關注網格佈局以及本系列翻譯,能夠關注公衆號「前端記事本」,及時得到最新消息推送。

相關文章
相關標籤/搜索