1. 程式人生 > 其它 >access網格線方向微為垂直_web前端入門到實戰:CSS 網格佈局:網格線

access網格線方向微為垂直_web前端入門到實戰:CSS 網格佈局:網格線

技術標籤:access網格線方向微為垂直

fd55a3ca-b334-eb11-8da9-e4434bdf6706.png

本系列第一篇講到如何建立網格容器,以及在容器元素上能夠使用的屬性。網格格式化上下文一旦建立,你也就有了網格線了。有了網格線,你就能在網格專案上新增屬性,對專案做定位(place items)了。

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

  • 定位屬性:grid-column-startgrid-column-endgrid-row-startgrid-row-end 以及對應的簡寫屬性 grid-columngrid-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;
}

效果:

ff55a3ca-b334-eb11-8da9-e4434bdf6706.png

注意,雖然 .item 的內容很少,但還是佔滿了整個定位區域。這是因為專案上的對齊屬性 align-selfjustify-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-startgrid-column-startgrid-row-endgrid-column-end。如果你是在水平、從左到右的語言環境下開發的(比如英語),那麼這幾個分別對應的方向是 topleftbottomright——跟設定 margin 的方向是相反的——逆時針。

這種設定網格線的方式是為了能適配不同的書寫模式(下面會介紹)——先設定起始端,在設定結束端,這與代表物理方向的 topleft... 是不同的。當然,上面這種設定專案位置的方式我不會用,還是會使用 grid-columngrid-row 這兩個簡寫屬性,因為它們的可讀性更高。

顯式網格中的網格線

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

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

0156a3ca-b334-eb11-8da9-e4434bdf6706.png
這裡的“行內方向”和“塊方向”的概念需要介紹一下:
我們平時在開發網站時,所瀏覽中、英文網頁文字排版方式,基本都是從左到右、從上到下的。我們把> 文字書寫方向就叫做行內方向(inline direction),文字折行方向叫做塊方向(block direction)。
同樣的,如果是垂直書寫語言——像中國古籍裡排版方式——那麼從上到下就是指行內方向,從右到左是塊方向。

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

0556a3ca-b334-eb11-8da9-e4434bdf6706.png

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

0756a3ca-b334-eb11-8da9-e4434bdf6706.png

因此,網格線的編號是跟書寫模式、文件或元件的語言環境存在一定關係。

另外,顯式網格的最後一根網格線可以使用數值 -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>

我們來看看結果:

0956a3ca-b334-eb11-8da9-e4434bdf6706.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;
}

效果:

0a56a3ca-b334-eb11-8da9-e4434bdf6706.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>

效果:

0b56a3ca-b334-eb11-8da9-e4434bdf6706.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>

來看看效果:

0c56a3ca-b334-eb11-8da9-e4434bdf6706.png

將來 grid-template-columnsgrid-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 值):

0e56a3ca-b334-eb11-8da9-e4434bdf6706.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>

效果:

1356a3ca-b334-eb11-8da9-e4434bdf6706.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>

效果:

1556a3ca-b334-eb11-8da9-e4434bdf6706.png

網格預設的定位行為是這樣的:如果當前剩餘的空白空間不足以放得下專案,那麼就換行顯示,這樣就會導致上一行會留下空白。你可以通過設定 grid-auto-flow 值為 dense(該單詞為“密集”的意思,意思即儘可能密集的排列專案)來控制這種行為。在這種情況下,如果當前剩下的空白區域足以放得下後續的某個專案,那麼這個後續專案會自動擠上來顯示,這會導致顯示順序與原始碼順序不一致。我們對上例稍作修改,新增一個grid-auto-flow: dense 設定。結果發現專案 3 放在專案 2 之前顯示了。

.grid {
  /* ... */
  grid-auto-flow: dense; /* 增加了這一句 */
}

效果:

1756a3ca-b334-eb11-8da9-e4434bdf6706.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;
}

效果:

1856a3ca-b334-eb11-8da9-e4434bdf6706.png

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

注意,在動圖的最後我還做了一件事情,就是在網格容器上設定了 grid-auto-flow: dense,導致第六個專案位置上移了。這是為了讓大家區分自動定位與密集定位:

  • 自動定位在佔據空白的同時,會遵守專案順序——排到空間區域的專案順序與原始碼中出現的順序是一致的。
  • 而密集定位則不管順序——只要空白空間放得下我,我就要過去。

自動定位演算法非常值得我們理解的。這對於理解某些場景下的佈局表現會有幫助——比如,如果在網格中新增加了一個專案但沒有設定定位區域,則它可能不會像我們所想的那樣排在網格的最後面,而是出現在比較靠前的某個“奇怪”位置。

總結

關於網格線的內容還是挺多的。需要記住的是,網格行號從網格創建出來的那一刻起就隨之產生,你可以通過指定初始行號和結束行號來定位一個專案。在下一篇文章,我還會介紹另一個定位網格專案的形式:grid-template-areas

(正文完)

從最零基礎開始的的HTML+CSS+JavaScript。jQuery,Ajax,node,angular框架等到移動端HTML5的專案實戰【視訊+工具+系統路線圖】都有整理,線上解析,學習指導,點:【WEB前端學習圈⑤】