[譯] 理解 CSS 網格佈局:網格線

原文連接:Understanding CSS Grid: Grid Lines,by Rachel Andrewcss

Photo by Ridham Nagralawala

本文是講解網格佈局系列的第二篇,教你從網格佈局新手到專家。html

本系列第一篇講到如何建立網格容器,以及在容器元素上可以使用的屬性。網格格式化上下文一旦建立,你也就有了網格線了。有了網格線,你就能在網格項目上添加屬性,對項目作定位(place items)了。算法

讀完本篇文章,你將學到:跨域

  • 定位屬性:grid-column-startgrid-column-endgrid-row-startgrid-row-end 以及對應的簡寫屬性 grid-column 和 grid-row
  • 如何使用行號(line number)設置 grid-area 屬性。
  • 如何根據命名網格線(line name)定位項目。
  • 在定位項目時,顯式網格和隱式網格上的表現有何不一樣。
  • 使用 span 關鍵字,再講一點福利內容 subgrid。
  • 當混合使用自動佈局(auto-placed)和肯定佈局(placed)定位項目時,須要注意些什麼。

網格線定位

在網格中定位一個項目時,須要先設置它從哪根線開始,到哪兒根線結束。舉個例子,我要在一個 5x5 的網格中定位一個項目,讓它佔據第二列和第三列,第一行到第三行。我會使用下面的 CSS 代碼(注意,這裏使用的是網格線,而非網格軌道)。函數

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

上面的代碼還能夠簡寫爲如下形式:斜線以前表示起始線(start line),斜線以後表示終止線(end line)。佈局

.item {
  grid-column: 2 / 4;
  grid-row: 1 / 4;
}
複製代碼

效果(demo):
post

image.png

注意,雖然 .item 的內容不多,但仍是佔滿了整個定位區域。這是由於項目上的對齊屬性 align-selfjustify-self 的默認值爲 stretch網站

若是項目只需跨越一個軌道,那麼能夠忽略設置終止線,由於項目默認就跨域一個軌道。舉個例子,設置一個只佔據第二列的項目。以前會這麼寫:ui

.item {
  grid-column: 2 / 3;
}
複製代碼

其實能夠簡寫成這樣的:spa

.item {
  grid-column: 2;
}
複製代碼

grid-area 屬性定位

咱們還能用 grid-area 屬性定位項目。下一篇文章會全面講它的用法,不過如今咱們只講使用行號來設置它的方式:

.item {
  grid-area: 1 / 2 / 4 / 4;
}
複製代碼

grid-area 屬性行號的設置順序是這樣的:grid-row-startgrid-column-startgrid-row-endgrid-column-end。若是你是在水平、從左到右的語言環境下開發的(好比英語),那麼這幾個分別對應的方向是 topleftbottomright——跟設置 margin 的方向是相反的——逆時針。

這種設置網格線的方式是爲了能適配不一樣的書寫模式(下面會介紹)——先設置起始端,在設置結束端,這與表明物理方向的 topleft... 是不一樣的。固然,上面這種設置項目位置的方式我不會用,仍是會使用 grid-columngrid-row 這兩個簡寫屬性,由於它們的可讀性更高。

顯式網格中的網格線

在一個網格容器中,使用 grid-template-columnsgrid-template-rows 設置的那部分網格區域稱爲 顯式網格。在定義顯式區域的同時,還會定義網格線。

這些網格線會編號,起始值是 1,在行內和塊方向兩個維度上編號。對水平書寫模式、從左向右排版的語言來講:行內方向(inline direction)的編號從左開始;塊方向(block direction)的編號則從上面開始。

image.png

這裏的「行內方向」和「塊方向」的概念須要介紹一下:

咱們平時在開發網站時,所瀏覽中、英文網頁文本排版方式,基本都是從左到右、從上到下的。咱們把> 文字書寫方向就叫作行內方向(inline direction),文字折行方向叫作塊方向(block direction)。

一樣的,若是是垂直書寫語言——像中國古籍裏排版方式——那麼從上到下就是指行內方向,從右到左是塊方向。

若是是在水平 RTL(right to left)語言環境下,好比阿拉伯語。此時,塊方向仍然從上面開始編號,但行內方向編號就是從右開始的了。

image.png

固然,若是是在垂直書寫模式下,好比下圖裏的網格就設置了  writing-mode: vertical-rl。那麼塊方向則是從右面開始編號的,行內方向則從上面開始編號。


所以,網格線的編號是跟書寫模式、文檔或組件的語言環境存在必定關係。

另外,顯式網格的最後一根網格線可使用數值 -1 指代,同理倒數第二第三跟網格線分別是 -2-3,依次類推。假設·,如今有一個項目從網格的第一列橫跨到最後一列,那麼能夠這樣寫:

.item {
  grid-column: 1 / -1;
}
複製代碼

隱式網格中的網格線

隱形網格的網格線也是從 1 開始編號的。假設我建立一個網格,只顯式指定了列(使用 grid-template-columns 屬性),並未顯式指定行,只使用 grid-auto-rows: 5em 指定了隱式行的尺寸。

在下面的網格佈局中,我爲一個項目添加了 .placed 類,指定它從第一行跨越到最後一行。

<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div class="placed">Placed</div>
</div>

<style> .grid { display: grid; grid-template-columns: repeat(5, 100px); grid-auto-rows: 5em; } .grid > .placed { background-color: orange; grid-row: 1 / -1; /* the end line is in the implicit grid so -1 does not resolve to it*/ } </style>
複製代碼


咱們來看看結果(demo):

image.png

.placed 的定位結果與咱們想象的有出入,按道理應該佔兩行纔對,實際只佔了一行。這是由於如今的行軌道沒有使用 grid-template-rows 顯式建立,致使行號 -1 被解析爲 2,而非 3

如今尚未辦法定位到隱式網格中的最後一根網格線,由於並不知道一共有多根網格線。

使用命名網格線定位項目

除了使用行號定位項目,咱們還你能使用命名網格線來定位項目。一條網格線能夠取多個名字,名字包圍在方括號 [] 中,網格線名稱在各軌道尺寸(tracks sizes)之間定義的。

.grid {
  display: grid;
  grid-template-columns: [full-start] 1fr [main-start] 2fr 2fr [main-end full-end];
}
複製代碼

有了命名網格線,就能夠用它來替換默認行號來定位項目。

.item {
  grid-column: main-start / main-end;
}
複製代碼

效果(demo):

image.png

若是一根網格線定義了多個名字,那麼你能夠任選其一使用。這麼多名稱最終都是指代同一根網格線。

如何處理多個網格線重名的狀況?

這是一個頗有趣的場景,多個網格線使用了同一個名字。這會發生在使用了 repeat() 函數的地方。下面例子中,我定義了一個八列網格,是經過 repeat(4, [sm] 1fr [lg] 2fr) 重複四次獲得結果。還將較小軌道尺寸左邊的網格線命名爲 sm,較大軌道尺寸左邊的網格線則命名爲 lg

這時,若是要指定是具體哪根網格線的時候,就要用到索引了。好比,我想把一個項目從第二根 sm 網格線延伸到第三根 lg 網格線,我會使用 grid-column: sm 2 / lg 3。另外,若是沒給網格線指定索引的狀況下,默認將解析到第一根叫這個名字的網格線。

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

<style> .grid { display: grid; grid-template-columns: repeat(4, [sm] 1fr [lg] 2fr); grid-template-rows: repeat(5, 50px); } .item { grid-column: sm 2 / lg 3; grid-row: 1 / 4; } </style>
複製代碼

效果(demo):

image.png

使用關鍵字 span

有些狀況,只須要一個項目跨越必定數量的軌道,但不知道確切的網格位置。好比,當使用自動定位算法(auto-placement)定位項目的時候,只知道它們跨越了多個軌道,而非默認的就跨越一個。這個時候,就要使用關鍵字 span 了。

下面舉了一個例子, .item1 設置了 grid-column: auto / span 3

<div class="grid">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
</div>

<style> .grid { display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: repeat(5, 50px); } .item1 { grid-column: auto / span 3; } .item2 { grid-column: auto / span 2; grid-row: auto / span 2; } </style>
複製代碼

來看看效果(demo):

image.png

未來 grid-template-columns 和 grid-template-rows 屬性開始全面支持 subgrid 值以後,這種技術將變得很是有用。好比,在卡片佈局中,每一個卡片包含一個標題和內容區域,咱們但願這些卡片裏的內容也是彼此對齊的,那麼能夠經過爲卡片設置 grid-template-rows 設置爲 subgrid 來控制卡片從父網格中繼承(兩)行,這樣就能實現卡片內容的自動對齊效果了。

<div class="grid">
  <article class="card">
    <h2>This is the heading</h2>
    <p>This is the body of the card.</p>
  </article>
  <article class="card">
    <h2>This is the heading and some headings are bigger</h2>
    <p>This is the body of the card.</p>
  </article>
	<!-- ... -->
</div>

<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); } /* * 1. `.card` 既是一個網格項目(隸屬於 `.grid`),也是一個網格容器。 * 2. `.card` 做爲網格項目佔據兩行軌道,它在行上的行爲表現會傳遞給做爲容器的它的子項目。 * / .card { grid-row: auto / span 2; /* 2 */ display: grid; /* 1 */ grid-template-rows: subgrid; /* 2 */ } </style>
複製代碼

看下效果(demo。在 Firfox 中查看,Chrome 中目前不支持 subgrid 值):

image.png

基於網格線定位層疊項目

網格系統會自動將項目定位到網格上的空單元格中,而不會遇到項目被定位到同一個單元格中的狀況。可是能夠基於網格行號、將不一樣的項目放入同一網格單元中。下例中,我設置了一個跨越兩行軌道的圖片,還有一個位於第二行軌道的有半透明背景效果的標題文本。

<div class="grid">
  <figure>
    <img src="https://images.unsplash.com/photo-1576451930877-c838b861e9b6?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ" alt="lights">
    <figcaption>This is the caption</figcaption>
  </figure>
  <!-- ... -->
</div>

<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } figure { display: grid; grid-template-rows: 300px min-content; } figure img { object-fit: cover; width: 100%; height: 100%; grid-row: 1 / 3; grid-column: 1; } figcaption { grid-row: 2; grid-column: 1; background-color: rgba(0,0,0,.5); color: #fff; padding: 10px; } </style>
複製代碼

效果(demo):

image.png

這些項目將按照它們在 HTML 中出現的順序排列。上例中,標題處於圖片以後,所以會顯示在圖片上面。若是標題在前面,那麼它就會擋在圖片後面,咱們就看不見了。另外,若是標題必須在圖片前面,那麼你能夠經過使用 z-index 屬性來控制層疊順序,讓圖片顯示。

混合使用網格線定位與自動定位

若是你混合使用網格線定位與自動定位,須要多加當心。當項目是根據自動定位算法定位的時候,會依次將本身定位到網格上、下一個可用的空白空間。

<div class="grid">
  <figure>...</figure>
  <figure>...</figure>
  <figure>...</figure>
	<!-- ... -->
</div>

<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); } figure { margin: 0; display: grid; grid-template-rows: 200px min-content; } figure:nth-child(odd) { grid-column: auto / span 2; } figure:nth-child(2) { grid-column: auto / span 3; } </style>
複製代碼

效果(demo):

GIF.gif

網格默認的定位行爲是這樣的:若是當前剩餘的空白空間不足以放得下項目,那麼就換行顯示,這樣就會致使上一行會留下空白。你能夠經過設置 grid-auto-flow 值爲 dense(該單詞爲「密集」的意思,意思即儘量密集的排列項目)來控制這種行爲。在這種狀況下,若是當前剩下的空白區域足以放得下後續的某個項目,那麼這個後續項目會自動擠上來顯示,這會致使顯示順序與源碼順序不一致。咱們對上例稍做修改,添加一個grid-auto-flow: dense 設置。結果發現項目 3 放在項目 2 以前顯示了。

.grid {
  /* ... */
  grid-auto-flow: dense; /* 增長了這一句 */
}
複製代碼

效果(demo):

image.png

請注意,此行爲可能會致使用戶使用 Tab 鍵瀏覽文檔時出現問題,由於視順序與源碼順序不一樣。自動定位算法會尋找第一個可用的間隙來排佈網格項目。打個比方:佈局時把頭幾個網格項目避開頂部區域,留下空白,那麼自動定位算法會將後續合適尺寸的項目安排到這些軌道中。

我這裏再舉一個例子(也是本篇最後一個例子):咱們基於行號定位(第 1 項和第 2 項)將第一行的空間空了下來,隨後會看到後來的項目會向上移動來填補這些空白空間。

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}

figure:nth-child(odd) {
  grid-column: auto / span 2;
}

figure:nth-child(1) {
  grid-row: 2;
  grid-column: 1;
}

figure:nth-child(2) {
  grid-row: 2;
  grid-column: 2 / -1;
}
複製代碼

效果(demo):

GIF.gif

看到沒?第1、第二個項目被定位到第二行顯示了,空下來了第一行,這時後續的第3、第四個項目被自動定位算法推到了第一行。

注意,在動圖的最後我還作了一件事情,就是在網格容器上設置了 grid-auto-flow: dense,致使第六個項目位置上移了。這是爲了讓你們區分自動定位與密集定位:

  • 自動定位在佔據空白的同時,會遵照項目順序——排到空間區域的項目順序與源碼中出現的順序是一致的。
  • 而密集定位則無論順序——只要空白空間放得下我,我就要過去。

自動定位算法很是值得咱們理解的。這對於理解某些場景下的佈局表現會有幫助——好比,若是在網格中新增長了一個項目但沒有設置定位區域,則它可能不會像咱們所想的那樣排在網格的最後面,而是出如今比較靠前的某個「奇怪」位置。

總結

關於網格線的內容仍是挺多的。須要記住的是,網格行號從網格建立出來的那一刻起就隨之產生,你能夠經過指定初始行號和結束行號來定位一個項目。在下一篇文章,我還會介紹另外一個定位網格項目的形式:grid-template-areas

(正文完)


廣告時間(長期有效)

我有一位好朋友開了一間貓舍,在此幫她宣傳一下。如今貓舍裏養的都是布偶貓。若是你也是個愛貓人士而且有須要的話,不妨掃一掃她的【閒魚】二維碼。不買也沒關係,看看也行。

(完)

相關文章
相關標籤/搜索