原文連接:Understanding CSS Grid: Grid Lines,by Rachel Andrewcss
本文是講解網格佈局系列的第二篇,教你從網格佈局新手到專家。html
本系列第一篇講到如何建立網格容器,以及在容器元素上可以使用的屬性。網格格式化上下文一旦建立,你也就有了網格線了。有了網格線,你就能在網格項目上添加屬性,對項目作定位(place items)了。算法
讀完本篇文章,你將學到:跨域
grid-column-start
、grid-column-end
、grid-row-start
、grid-row-end
以及對應的簡寫屬性 grid-column
和 grid-row
。grid-area
屬性。在網格中定位一個項目時,須要先設置它從哪根線開始,到哪兒根線結束。舉個例子,我要在一個 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
注意,雖然 .item
的內容不多,但仍是佔滿了整個定位區域。這是由於項目上的對齊屬性 align-self
和 justify-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-start
、grid-column-start
、grid-row-end
、grid-column-end
。若是你是在水平、從左到右的語言環境下開發的(好比英語),那麼這幾個分別對應的方向是 top
、left
、bottom
和 right
——跟設置 margin
的方向是相反的——逆時針。
這種設置網格線的方式是爲了能適配不一樣的書寫模式(下面會介紹)——先設置起始端,在設置結束端,這與表明物理方向的 top
、left
... 是不一樣的。固然,上面這種設置項目位置的方式我不會用,仍是會使用 grid-column
和 grid-row
這兩個簡寫屬性,由於它們的可讀性更高。
在一個網格容器中,使用 grid-template-columns
或 grid-template-rows
設置的那部分網格區域稱爲 顯式網格。在定義顯式區域的同時,還會定義網格線。
這些網格線會編號,起始值是 1
,在行內和塊方向兩個維度上編號。對水平書寫模式、從左向右排版的語言來講:行內方向(inline direction)的編號從左開始;塊方向(block direction)的編號則從上面開始。
這裏的「行內方向」和「塊方向」的概念須要介紹一下:
咱們平時在開發網站時,所瀏覽中、英文網頁文本排版方式,基本都是從左到右、從上到下的。咱們把> 文字書寫方向就叫作行內方向(inline direction),文字折行方向叫作塊方向(block direction)。
一樣的,若是是垂直書寫語言——像中國古籍裏排版方式——那麼從上到下就是指行內方向,從右到左是塊方向。
若是是在水平 RTL(right to left)語言環境下,好比阿拉伯語。此時,塊方向仍然從上面開始編號,但行內方向編號就是從右開始的了。
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):
.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):
若是一根網格線定義了多個名字,那麼你能夠任選其一使用。這麼多名稱最終都是指代同一根網格線。
這是一個頗有趣的場景,多個網格線使用了同一個名字。這會發生在使用了 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):
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):
未來 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
值):
網格系統會自動將項目定位到網格上的空單元格中,而不會遇到項目被定位到同一個單元格中的狀況。可是能夠基於網格行號、將不一樣的項目放入同一網格單元中。下例中,我設置了一個跨越兩行軌道的圖片,還有一個位於第二行軌道的有半透明背景效果的標題文本。
<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):
這些項目將按照它們在 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):
網格默認的定位行爲是這樣的:若是當前剩餘的空白空間不足以放得下項目,那麼就換行顯示,這樣就會致使上一行會留下空白。你能夠經過設置 grid-auto-flow
值爲 dense
(該單詞爲「密集」的意思,意思即儘量密集的排列項目)來控制這種行爲。在這種狀況下,若是當前剩下的空白區域足以放得下後續的某個項目,那麼這個後續項目會自動擠上來顯示,這會致使顯示順序與源碼順序不一致。咱們對上例稍做修改,添加一個grid-auto-flow: dense
設置。結果發現項目 3 放在項目 2 以前顯示了。
.grid {
/* ... */
grid-auto-flow: dense; /* 增長了這一句 */
}
複製代碼
效果(demo):
請注意,此行爲可能會致使用戶使用 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):
看到沒?第1、第二個項目被定位到第二行顯示了,空下來了第一行,這時後續的第3、第四個項目被自動定位算法推到了第一行。
注意,在動圖的最後我還作了一件事情,就是在網格容器上設置了 grid-auto-flow: dense
,致使第六個項目位置上移了。這是爲了讓你們區分自動定位與密集定位:
自動定位算法很是值得咱們理解的。這對於理解某些場景下的佈局表現會有幫助——好比,若是在網格中新增長了一個項目但沒有設置定位區域,則它可能不會像咱們所想的那樣排在網格的最後面,而是出如今比較靠前的某個「奇怪」位置。
關於網格線的內容仍是挺多的。須要記住的是,網格行號從網格建立出來的那一刻起就隨之產生,你能夠經過指定初始行號和結束行號來定位一個項目。在下一篇文章,我還會介紹另外一個定位網格項目的形式:grid-template-areas
。
(正文完)
廣告時間(長期有效)
我有一位好朋友開了一間貓舍,在此幫她宣傳一下。如今貓舍裏養的都是布偶貓。若是你也是個愛貓人士而且有須要的話,不妨掃一掃她的【閒魚】二維碼。不買也沒關係,看看也行。
(完)