[CSS] Flex/Grid Layout Modules, part 12

今天继续来讲 Grid 单元,昨天提到了对齐基本用法,今天继续来讲对齐与留白。不过一开始,还是先解释清楚关於格线与单元之间的事情。

总觉得 15 天就会结束了说(笑)。


单元与格线

Grid 容器提供了格线系统,然後每个格线将内容区块化(blockification)後,产生了 Grid 单元。这是整个 Grid Layout 的运作方式。那麽,对於 Grid 单元来说,格线系统就类似一种边界,可以指定 Grid 单元在哪些轨道上。

基本的样式为,

样式 可用值 预设值
grid-row-start, grid-row-end <轨道格线> auto
grid-column-start, grid-column-end <轨道格线> auto
grid-row <grid-row-start> / <grid-row-end>? auto
grid-column <grid-column-start> / <grid-column-end>? auto
grid-area 轨道区域名称或 <grid-row> / <grid-column>? 集合,定义顺序为 row-start column-start row-end column-end auto

指定轨道区域名称

首先,轨道区域名称比较容易理解,他是对应於 Grid 容器的 grid-template-areas 所指定的名称,例如,

.grid-container {
    display: grid;
    
    grid-template-areas:
        "nav nav nav"
        "sidebar main main"
        "sidebar main main"
        "footer footer footer"
}

那麽当你想要把你的 Grid 单元放到指定区域名称的时候,使用 grid-area 就会比较方便,

.grid-nav {
    grid-area: nav;
}

.grid-sidebar {
    grid-area: sidebar;
}

.grid-main {
    grid-area: main;
}

.grid-footer {
    grid-area: footer;
}

https://ithelp.ithome.com.tw/upload/images/20210917/20001433Us6uvvdP5Y.png

不知道大家还记得在开始的时候提到的网格单元容器吗?

不知道的自己去复习

当你使用 grid-template-areas 定义区块,然後接着使用 grid-area 来指定自订区域名称的时候,基本上就等同於 指定一个轨道区域 给这个 Grid 单元使用,所以,基本上他可以被翻译成网格轨道格线的定义。

我们拿刚刚的例子来看,

.grid-nav {
    grid-area: nav;
}

/* 等同於 */

.grid-nav {
    grid-area: 1 1 2 4;
}

/* 等同於 */

.grid-nav {
    grid-row: 1 / 2;
    grid-column: 1 / 4;
}

/* 等同於 */

.grid-nav {
    grid-row: nav-start / nav-end;
    grid-column: nav-start / nav-end;
}

/* 等同於 */

.grid-nav {
    grid-row-start: 1;
    grid-row-end: 2;
    
    grid-column-start: 1;
    grid-column-end: 4;
}

/* 等同於 */

.grid-nav {
    grid-row-start: nav-start;
    grid-row-end: nav-end;
    
    grid-column-start: nav-start;
    grid-column-end: nav-end;
}

所以说,这边的定义就会是一个所谓的网格单元容器(Grid item container block),根据一开始提到的定位点问题,使用 grid-area 的时候,请留意你的 Grid 单元在使用 position: absolute 的情况。之前已经说过了,这边就不再多做赘述。

我们回到 grid-area 这件事情上面。当我们使用了命名单元的时候,如同之前所提到的,会提供 4 条隐性格线。所以当你使用 nav-startnav-end 的时候也是会发生作用的。

忘记的人请回去复习谢谢

接着,这个网格单元容器跟轨道一样,是一种边界的概念,换句话说,他一样没有能力去局限 Grid 单元本身的定义或内容是否不能超出边界(轨道)。另外,当你的单元轨道使用的轨道名称,不存在於 Grid 容器定义里的话,会出现奇怪的问题。

那个奇怪的问题我上次也提过了,这边就不赘述了。


指定 <轨道格线>

我们之前有聊到轨道跟格线,还有隐性格线的介绍,现在我们就把他用在 Grid 单元上面。轨道格线的定义方式有几种,

可用值 说明
auto 不解释。
<自订轨道名称> 请避开 -start, -end,其余不解释。
<数字> 将你所指定的 <数字> 的轨道,可以是负数。
<数字> <自订轨道名称> <自订轨道名称> 的轨道有复数数量时,该数字仅会计算相同名称的轨道,如果数字是负数的话,计算方向就是反向,该数字不可为零 0
span [<数字>, <自订轨道名称>] 跨度(维度)的轨道,如果是 <数字> 则表示要 跨过多少轨道数量,如果是 <自订轨道名称> 则表示直接跨到该<自订轨道名称> 的轨道。该数字 不可为负数或 0

Grid 格线轨道这件事情之前已经有提过了,这边就不再继续解释说过的东西。我们直接举一些例子来看看使用方法,

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [boo] 1fr [qoo] 1fr [ooo];
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20210917/20001433d4ruHB6lcu.png

首先,基本的 Grid 单元轨道格线设定会是这样,

.grid-item {
    grid-column-start: foo;
    grid-column-end: qoo;
    
    grid-row-start: 2;
    grid-row-end: 3;
}

/* 等同於 */

.grid-item {
    grid-column-start: foo;
    grid-column-end: qoo;
    
    grid-row-start: -3;
    grid-row-end: -2;
}

https://ithelp.ithome.com.tw/upload/images/20210917/20001433xsUNJohV3E.png


<数字> <自订轨道名称>

接着我们来聊 <数字> <自订轨道名称> 这个设定方式,他有一个先决条件,

当你的自订轨道有复数相同的名称时,此设定才会正常,不然一样会触发隐性轨道的设置。

我们举几个例子来看看,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(7, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

https://ithelp.ithome.com.tw/upload/images/20210917/20001433Ul6yjxOPdV.png

接着我们来看比较正常定义的状态,

.grid-item-a {
    grid-column-start: foo;
    grid-column-end: 2 qoo;
    
    grid-row: auto;
}

好的,根据 <数字> <自订轨道名称> 的定义,我们的栏方向结束轨道是 第二个 qoo,所以你知道最後我们的网格单元会在那个位置上了吗?

https://ithelp.ithome.com.tw/upload/images/20210917/20001433DF2b3oLNSN.png

如果算错了怎麽办?举个例子来说,

.grid-item-b {
    grid-column-start: -3 foo;
    grid-column-end: -4 qoo;
    
    grid-row: auto;
}

阿我就怕被骂啊。

https://ithelp.ithome.com.tw/upload/images/20210917/20001433VCo3wl7VJS.png

如果起始与结束在同一个网格轨道上,网格单元会自动往 下一个轨道空间摆放

所以,刚刚写错的地方,他其实就是以下这样的设定方式,

.grid-item-b {
    grid-column-start: -3 foo;
    grid-column-end: -3 qoo;
    
    grid-row: auto;
}

无论你的数字是正值还是负值,基本上遇到一样的状况时,网格系统就是会这样去做处理。如果没空间可以放的话,那麽就会出现隐性网格轨道,用来摆放应该放进去的位置。举例来说,

/* 超出网格容器的轨道数量 */
.grid-item-b {
    grid-column-start: -9 foo;
    grid-column-end: 12 qoo;
    
    grid-row: auto;
}

图片我就不放了,上面设定的结果就是你会获得 12 条轨道。至於为什麽不要问我,稍微加点乘除一下就会知道了。


span [<数字>, <自订轨道名称>]

最後一种设定方式称之为跨度(跨维度)的 Grid 单元设定。所谓的跨维度,意思就是你可以指定你要 跨过 多少个轨道,

  • span 3 表示跨过三个轨道
  • span foo 表示跨过命名轨道 foo

这个关键字 span 有两种不同的呈现方式,你把他放在 -start-end 的两种位置上时,他的操作方式会略有不同。我们先来看看使用 -end 的状况,他比较容易理解,

.grid-item {
    grid-column-start: 1;
    grid-column-end: span 3;
    
    grid-row: auto;
}

我们在 grid-column-end 的设定是 span 3,他的意思就是,

grid-column-start 的设定开始,栏方向 往後 做跨度 3 个轨道的动作。如果是命名轨道,则是栏方向 往後 做 跨度直到 <命名轨道> 的动作。

https://ithelp.ithome.com.tw/upload/images/20210917/20001433aW4btNWUoE.png

用数字的方式很容易理解,如果今天使用的是 <命名轨道> 呢?跟往常在使用命名轨道的逻辑是相同的,他只会计算 符合名称的轨道,换句话说,如果他找不到你的轨道名称,那麽就会触发隐性轨道的事件发生。

我们先不谈隐性轨道,单纯以合法的方式来操作。在命名轨道的情况下,所谓的跨度的计算方式,在 -end 的设定方式下,他会往後找下一个符合命名轨道的轨道来做跨度的动作。所以,我们举一个名称比较多的轨道来当例子,会比较容易理解,

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [ooo] 1fr [ppp] 1fr [rrr] 1fr [boo] repeat(3, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

.grid-item:nth-of-type(1) {
    grid-column-start: 1;
    grid-column-end: span foo;
    
    grid-row: auto;
}

.grid-item:nth-of-type(2) {
    grid-column-start: zoo;
    grid-column-end: span qoo;
    
    grid-row: auto;
}

https://ithelp.ithome.com.tw/upload/images/20210917/200014338qxIyDGsKg.png

以上是使用在 -end 的情况,这个设定换成 grid-row-* 也是一样的,你就把他想成换了一个方向就可以了。

接着来谈谈 -start 配上 span 这件事情,或许你会觉得困惑,所谓的跨度不就是 往後跨格线轨道 这样吗?理论上对,但这是在 -end 的情况下,如果使用在 -start 的话,就会变成 往前跨格线轨道 的操作方式,是的,方向跟 -end 相反。

-end 使用 span往後跨度
-start 使用 span往前跨度

如果可以理解的话,那麽以下两种设定就只要了解 -end 的概念,然後把方向 反过来 就可以了,

  • grid-column-start: span 3grid-column-end 轨道 往前 跨度 3 个轨道。
  • grid-column-start: span boogrid-column-end 轨道 往前 跨度到 boo 轨道。

所以,如果这样使用会是什麽呈现方式呢?我用刚刚的 grid-column-end 的例子,然後把他做成 grid-column-start 的写法,然後 Grid 单元呈现会完全一样。

https://ithelp.ithome.com.tw/upload/images/20210917/200014338DgXSdzov8.png

以上就是 span 关键字的相关用法。我这边没有提到异常的处理方式,之後有机会再拿回来讲。毕竟,如果你只有 8 条格线轨道,你故意要跨 10 条轨道本来就会坏掉。所以这种情况我们暂时不在这里提,隐性轨道的事情讲起来太烦闷了。之後再来提会产生隐性轨道的事情吧。


关於 auto 与 Grid 单元轨道重叠

当你在设定一个比较复杂的格线系统时,可能有机会 算错轨道 或是 打错轨道名字 ,造成某些 Grid 单元在格线轨道设定的地方产生重叠。而这个重叠状况,就会产生两个单元互相覆盖的情形。

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [ooo] 1fr [ppp] 1fr [rrr] 1fr [boo] repeat(3, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

.grid-item:nth-of-type(1) {
    grid-column-start: 1;
    grid-column-end: 6;
    
    /* 指定在第一列 */
    grid-row: 1 / 2;
}

.grid-item:nth-of-type(2) {
    grid-column-start: foo;
    grid-column-end: span roo;
    
    /* 指定在第一列 */
    grid-row: 1 / 2;
}

https://ithelp.ithome.com.tw/upload/images/20210917/20001433SVJvm4abBe.png

在这种情况下,如果使用 auto 的话,又会有不一样的事情发生了,这些情况还需要看你是否有搭配 span 使用,组合起来会有各种不一样的事情发生。

grid-column-start grid-column-end 结果
auto 3 定位在第 3 轨道,往前跨 1 个轨道,产生一个格线单元,并覆盖相同位置的任何单元。
auto loo 定位在 loo 轨道上,往前跨 1 个轨道,产生一个格线单元,并覆盖相同位置的任何单元。
auto span 3 从上一个相同位置轨道的 最後一个轨道,往後跨 3 个轨道,产生一个格线单元。
auto span qoo 此设置无效,仅会从上一个相同位置轨道的 最後一个轨道,往後跨 1 个轨道,产生一个格线单元。
1 auto 定位在第 1 轨道,往後跨 1 个轨道,产生一个格线单元,并覆盖相同位置的任何单元。
loo auto 定位在 loo 轨道上,往後跨 1 个轨道,产生一个格线单元,并覆盖相同位置的任何单元。
span 3 auto 从上一个相同位置轨道的 最後一个轨道,往後跨 3 个轨道,产生一个格线单元。
span qoo auto 此设置无效,仅会从上一个相同位置轨道的 最後一个轨道,往後跨 1 个轨道,产生一个格线单元。

以上的状态换到 grid-row-* 也会是一样的情况,仅方向不同而已。上述的情况我就不做图片示意了,基本上稍微想像一下就好,我懒得作图了(灿笑)。


官方没有写的例外

扣除 autospan 之外,还有一种设定是合法的,但是 w3c 官方在这边并没有列出来,根据文件的部分也就如同我上面描述的东西而已,这个写法是,

<自订轨道名称> <数字>

这个写法等同於 <数字> <自订轨道名称>,如果下次看到有人这样写不用太意外。算是冷知识说出来让大家知道一下(笑)。


小记

这样就结束了吗?当然还有一点东西可以继续嘴,对齐跟定位的问题我们明天会继续讲。


目录与小节:
[CSS] Flex/Grid Layout Modules, part 1


部落格同步放送:
[CSS] Flex/Grid Layout Modules, part 12


<<:  day2: 程序码风格的重要性

>>:  Day 2. Pre-Start × WYSIWYG

Day 24. 事件处理 – v-on

v-on 在Vue.js 中我们可以使用v-on去监听 DOM 事件,当事件被触发时会呼叫我们设定的...

初学者跪着学JavaScript Day29 : async 和 await

一日客语:中文:成功 客语:ㄙㄣ3声 ㄍㄨㄥˊ siinˇ gungˊ 出现async、await可...

【资料结构】前中後运算式转置

前中後运算式转置 中置运算式是人脑的计算中最直观且最习惯理解的表示式,会将运算子(EX:加号)放在两...

多合一USB自动生成选单系统安装碟制作

我在十几年前就已经随身仅携带一支USB碟闯天下了, 不明白把多支随身碟串成钥匙圈或带光碟整理包出门的...

课堂笔记 - 物联网概论 课後测验

课後测验 单选题 感知层(单选题) 1.下列哪一项不属於物联网的应用? A.洗衣机於电费最低时段自...