網格佈局中的自動放置
CSS 網格佈局包含了一些規則,用於控制當你建立一個網格但沒有明確地將部分或全部子項放置到網格中時會發生什麼。當你不需要對內容放置進行顯式控制時,這種“自動放置”是為一組專案建立網格的最簡單方法。
預設放置
如果你沒有為專案提供放置資訊,它們會自動在網格上定位,將每個網格專案放置在一個網格單元中。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
自動放置的預設規則
正如你在上面的示例中看到的,如果你建立一個網格而沒有放置任何專案,子專案將自行佈局,每個網格單元中放置一個網格專案,並按原始碼順序排列。預設的流是按行排列專案。網格會將專案放置到第一行的每個單元格中。如果你使用 grid-template-rows 屬性建立了額外的行,那麼網格將繼續將專案放置在這些行中。如果網格的顯式網格中沒有足夠的行來放置所有專案,則會建立新的隱式行。
隱式網格中行的大小調整
隱式網格中自動建立的行的預設設定為自動調整大小。這意味著它們將根據新增的內容自行調整大小,而不會導致溢位。
這些行的大小可以透過 grid-auto-rows 屬性控制。例如,要使所有行高為 100px,你可以使用 grid-auto-rows: 100px;
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: 100px;
}
使用 minmax() 調整行的大小
minmax() 函式可以建立具有最小尺寸的行,並且在設定為 grid-auto-rows 值時,可以根據需要增長以適應內容。透過設定 grid-auto-rows: minmax(100px, auto);,我們將每行設定為至少 100px 高,同時允許每行根據需要儘可能高。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>
Four <br />This cell <br />Has extra <br />content. <br />Max is auto
<br />so the row expands.
</div>
<div>Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
使用軌道列表調整行的大小
你也可以傳入一個軌道列表。這將重複。下面的軌道列表將建立一個初始隱式行軌道為 100 畫素,第二個為 200px。只要內容被新增到隱式網格中,這就會繼續下去。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
grid-auto-rows: 100px 200px;
}
按列自動放置
你還可以要求網格按列自動放置專案。使用 grid-auto-flow 屬性,並將其值設定為 column。在這種情況下,網格將把你使用 grid-template-rows 定義的行中新增專案。當它填滿一列時,它會移動到下一個顯式列,或者在隱式網格中建立一個新的列軌道。與隱式行軌道一樣,這些列軌道也將自動調整大小。你可以使用 grid-auto-columns 控制隱式列軌道的大小。這與 grid-auto-rows 的工作方式相同。
在這個例子中,我們有一個網格,其中包含三條 200px 高的行軌道。我們宣告 grid-auto-flow: column; 以便按列自動放置。透過 grid-auto-columns: 300px 100px;,建立的列將交替為 300px 寬和 100px 寬,直到有足夠的列軌道容納所有專案。
.wrapper {
display: grid;
grid-template-rows: repeat(3, 200px);
gap: 10px;
grid-auto-flow: column;
grid-auto-columns: 300px 100px;
}
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
</div>
自動放置專案的順序
一個網格可以包含混合的專案放置方式。一些專案可能在網格上具有明確定義的位置,而另一些專案可能是自動放置的。如果你的文件順序反映了專案在網格上的順序,你可能不需要編寫 CSS 規則來放置所有內容。該規範包含一個詳細說明網格專案放置演算法的長篇章節;然而,對我們大多數人來說,我們只需要記住一些關於我們專案的規則。
修改了文件順序的順序
網格將未給定網格位置的專案按照規範中描述的“順序修改文件順序”放置。這意味著,如果你使用了 order 屬性,專案將按照該順序放置,而不是它們的 DOM 順序。否則,它們預設將按照它們在文件源中輸入的順序排列。
具有放置屬性的專案
網格首先會放置具有位置的任何專案。在下面的示例中,我有 12 個網格專案。專案 2 和專案 5 已使用基於行的放置方式放置在網格上。你可以看到這些專案是如何放置的,然後其他專案會自動放置在空白處。自動放置的專案會按照 DOM 順序放置在已放置專案之前,它們不會在位於它們之前的已放置專案的位置之後開始。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
處理跨軌道的專案
你可以在利用自動放置的同時使用放置屬性。在下一個示例中,我透過將專案 1、5 和 9 (4n+1) 設定為跨越兩行和兩列軌道來增強佈局。我透過 grid-column-end 和 grid-row-end 屬性並將其值設定為 span 2 來實現。這意味著專案的起始線將由自動放置設定,而結束線將跨越兩個軌道。
你可以看到這如何在網格中留下空白,因為對於自動放置的專案,如果網格遇到一個不適合軌道的專案,它將移動到下一行,直到找到一個專案可以容納的空間。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
}
.wrapper div:nth-child(4n + 1) {
grid-column-end: span 2;
grid-row-end: span 2;
background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
填補空隙
到目前為止,除了我們明確放置的專案外,網格始終向前推進並保持專案在 DOM 順序中。這通常是你想要的,例如,如果你正在佈局一個表單,你不會希望標籤和欄位為了填補一些空白而混淆。然而,有時,我們佈局的東西沒有邏輯順序,我們希望建立一個沒有空白的佈局。
要做到這一點,在容器上新增屬性 grid-auto-flow,並將其值設定為 dense。這與你用來將流順序更改為 column 的屬性相同,因此如果你在列中工作,你將同時新增兩個值 grid-auto-flow: column dense。
完成此操作後,網格現在將回填空白,因為它在網格中移動時像以前一樣留下空白,但如果它發現一個適合先前空白的專案,它將拿起該專案並將其從 DOM 順序中取出以放置在空白中。與網格中的任何其他重新排序一樣,這不會改變邏輯順序。例如,Tab 鍵順序仍將遵循文件順序。我們將在網格佈局和可訪問性指南中探討網格佈局的潛在可訪問性問題,但你在建立這種視覺順序和顯示順序之間的不一致時應謹慎。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div>Eight</div>
<div>Nine</div>
<div>Ten</div>
<div>Eleven</div>
<div>Twelve</div>
</div>
.wrapper div:nth-child(4n + 1) {
grid-column-end: span 2;
grid-row-end: span 2;
background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
grid-auto-flow: dense;
}
匿名網格專案
規範中提到了匿名網格項。如果你在網格容器內有一段未被任何其他元素包裹的文字字串,就會建立這些項。在下面的示例中,我們有三個網格項,假設你已將父級類為 grid 的元素設定為 display: grid。第一個是匿名項,因為它沒有封閉的標記,這個項將始終透過自動放置規則處理。另外兩個是包裹在 div 中的網格項,它們可以自動放置,或者你可以使用定位方法將它們放置到網格上。
<div class="grid">
I am a string and will become an anonymous item
<div>A grid item</div>
<div>A grid item</div>
</div>
匿名項總是自動放置的,因為無法定位它們。因此,如果你的網格中出於某種原因有未包裝的文字,請注意它可能會出現在意想不到的地方,因為它將根據自動放置規則進行自動放置。
自動放置的用例
當你有一組專案時,自動放置非常有用。這可能是不具有邏輯順序的專案,例如照片畫廊或產品列表。在這種情況下,你可能會選擇使用緊密打包模式來填補網格中的任何空洞。在我的圖片畫廊示例中,我有一些橫向和一些縱向圖片。我將橫向圖片(帶有 landscape 類)設定為跨越兩個列軌道。然後我使用 grid-auto-flow: dense 來建立一個緊密打包的網格。
嘗試刪除 grid-auto-flow: dense 這行,檢視內容如何重排以在佈局中留下空白。
<ul class="wrapper">
<li>
<img
alt="A colorful hot air balloon against a clear sky"
src="https://mdn.github.io/shared-assets/images/examples/balloon.jpg" />
</li>
<li class="landscape">
<img
alt="Three hot air balloons against a clear sky, as seen from the ground"
src="https://mdn.github.io/shared-assets/images/examples/balloons-small.jpg" />
</li>
<li class="landscape">
<img
alt="Three hot air balloons against a clear sky, as seen from the ground"
src="https://mdn.github.io/shared-assets/images/examples/balloons-small.jpg" />
</li>
<li class="landscape">
<img
alt="Three hot air balloons against a clear sky, as seen from the ground"
src="https://mdn.github.io/shared-assets/images/examples/balloons-small.jpg" />
</li>
<li>
<img
alt="A colorful hot air balloon against a clear sky"
src="https://mdn.github.io/shared-assets/images/examples/balloon.jpg" />
</li>
<li>
<img
alt="A colorful hot air balloon against a clear sky"
src="https://mdn.github.io/shared-assets/images/examples/balloon.jpg" />
</li>
</ul>
.wrapper {
display: grid;
grid-template-columns: repeat(3, minmax(120px, 1fr));
gap: 10px;
grid-auto-flow: dense;
}
.wrapper li.landscape {
grid-column-end: span 2;
}
自動放置還可以幫助你佈局具有邏輯順序的介面專案。一個例子是下一個示例中的定義列表。定義列表是一種有趣的樣式挑戰,因為它們是扁平的,沒有任何東西包裹著 dt 和 dd 項組。在我的示例中,我允許自動放置專案,但是我有類,它們將 dt 放在第 1 列,dd 放在第 2 列,這確保了術語在一側,定義在另一側——無論每種有多少。
<div class="wrapper">
<dl>
<dt>Mammals</dt>
<dd>Cat</dd>
<dd>Dog</dd>
<dd>Mouse</dd>
<dt>Birds</dt>
<dd>Pied Wagtail</dd>
<dd>Owl</dd>
<dt>Fish</dt>
<dd>Guppy</dd>
</dl>
</div>
dl {
display: grid;
grid-template-columns: auto 1fr;
max-width: 300px;
margin: 1em;
line-height: 1.4;
}
dt {
grid-column: 1;
font-weight: bold;
}
dd {
grid-column: 2;
}
自動放置目前(還)不能做什麼?
有一些問題經常被提及。目前我們還不能做到像用我們的專案定位網格的每個其他單元格。如果你遵循了關於網格上命名行的上一個指南,一個相關的問題可能已經浮現在腦海中。那就是定義一個規則,說明“將專案自動放置到下一個名為‘n’的行上”,然後網格將跳過其他行。關於這個問題在 CSSWG GitHub 儲存庫上已經有人提出了,歡迎你新增你自己的用例。
你可能會為自動放置或網格佈局的任何其他部分提出自己的用例。如果你這樣做了,請將它們作為問題提出,或新增到現有問題中,這可能解決你的用例。這將有助於使未來的規範版本更好。