access網格線方向微為垂直_web前端入門到實戰:CSS 網格佈局:網格線
技術標籤:access網格線方向微為垂直
本系列第一篇講到如何建立網格容器,以及在容器元素上能夠使用的屬性。網格格式化上下文一旦建立,你也就有了網格線了。有了網格線,你就能在網格專案上新增屬性,對專案做定位(place items)了。
讀完本篇文章,你將學到:
- 定位屬性:
grid-column-start
、grid-column-end
、grid-row-start
、grid-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;
}
效果:
注意,雖然 .item
的內容很少,但還是佔滿了整個定位區域。這是因為專案上的對齊屬性 align-self
和 justify-self
的預設值為 stretch
。
如果專案只需跨越一個軌道,那麼可以忽略設定終止線,因為專案預設就跨域一個軌道。舉個例子,設定一個只佔據第二列的專案。之前會這麼寫:
.item { grid-column: 2 / 3; }
其實可以簡寫成這樣的:
.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>
我們來看看結果:
.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;
}
效果:
如果一根網格線定義了多個名字,那麼你可以任選其一使用。這麼多名稱最終都是指代同一根網格線。
如何處理多個網格線重名的情況?
這是一個很有趣的場景,多個網格線使用了同一個名字。這會發生在使用了 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>
效果:
使用關鍵字 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>
來看看效果:
將來 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>
看下效果。在 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>
效果:
這些專案將按照它們在 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>
效果:
網格預設的定位行為是這樣的:如果當前剩餘的空白空間不足以放得下專案,那麼就換行顯示,這樣就會導致上一行會留下空白。你可以通過設定 grid-auto-flow
值為 dense
(該單詞為“密集”的意思,意思即儘可能密集的排列專案)來控制這種行為。在這種情況下,如果當前剩下的空白區域足以放得下後續的某個專案,那麼這個後續專案會自動擠上來顯示,這會導致顯示順序與原始碼順序不一致。我們對上例稍作修改,新增一個grid-auto-flow: dense
設定。結果發現專案 3 放在專案 2 之前顯示了。
.grid {
/* ... */
grid-auto-flow: dense; /* 增加了這一句 */
}
效果:
請注意,此行為可能會導致使用者使用 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;
}
效果:
看到沒?第一、第二個專案被定位到第二行顯示了,空下來了第一行,這時後續的第三、第四個專案被自動定位演算法推到了第一行。
注意,在動圖的最後我還做了一件事情,就是在網格容器上設定了 grid-auto-flow: dense
,導致第六個專案位置上移了。這是為了讓大家區分自動定位與密集定位:
- 自動定位在佔據空白的同時,會遵守專案順序——排到空間區域的專案順序與原始碼中出現的順序是一致的。
- 而密集定位則不管順序——只要空白空間放得下我,我就要過去。
自動定位演算法非常值得我們理解的。這對於理解某些場景下的佈局表現會有幫助——比如,如果在網格中新增加了一個專案但沒有設定定位區域,則它可能不會像我們所想的那樣排在網格的最後面,而是出現在比較靠前的某個“奇怪”位置。
總結
關於網格線的內容還是挺多的。需要記住的是,網格行號從網格創建出來的那一刻起就隨之產生,你可以通過指定初始行號和結束行號來定位一個專案。在下一篇文章,我還會介紹另一個定位網格專案的形式:grid-template-areas
。
(正文完)
從最零基礎開始的的HTML+CSS+JavaScript。jQuery,Ajax,node,angular框架等到移動端HTML5的專案實戰【視訊+工具+系統路線圖】都有整理,線上解析,學習指導,點:【WEB前端學習圈⑤】