[CSS] Flex/Grid Layout Modules, part 11

现在终於可以开始讲 Grid 单元的事情了,虽然可以讲的事情可能不多,绝大部分会围绕在造成容器影响的地方,当然基本的东西还是会先带一下。

只是说讲完之後到底能不能满 30 天呢 XD


Grid 单元

首先,他跟 Flexbox 一样,如果内容单元是包含在 Grid 容器里面的话,他本身是宣告成 Grid 格式的文本(Grid formatting context),他并不会因为你把他宣告成 Box Module 而转换成你所知道的区块元件(Block formatting context),在 Grid 容器内的元件,基本上都会被自动指定为 display: block 这样的样式。

同时,在一个 Grid 容器宣告为 display: griddisplay: inline-grid 当下,其内容所包含的元件会全部被区块化(blockification),也就是现在说的 Grid 单元。

有趣的地方在於,一个合法的 Grid 容器(其内容包含 Grid 单元),在改变区块样式时(例如:display: none),其 Grid 单元产生(DOMTree 渲染)的区块化还是会发生,说的比较白话一点就是,他还是会把 Grid 单元区块化动作完成之後,外层的 Grid 容器才会做 display: none 的动作。

但是,

如果 Grid 单元设定为 display:contents 则不在此列。关於这个设定我在整个 Grid 单元讲完之後再来讲这个特别的东西。其实我以前有约略讲过,有兴趣的人可以自己去看看 [CSS] 关於 Grid Layout 的使用姿势

另外,在相连的 Grid 单元如果宣告为非区块元件时,由於已经区块化了,所以基本上他还是会属於区块元件,他会阻断匿名区块元件的产生(anonymous block box)。举例来说,如果把 Grid 单元使用 display: table-cell 的设定,那麽他们最终会被转换成 display: block,并不会建立成匿名表格单元(anonymous table box)。

关於匿名区块这边就不多说了,有兴趣的我看最後有没有时间再来聊聊。

有兴趣可以看这里 2.4. Layout-Internal Display Types: the table-* and ruby-* keywords


尺寸

Grid 单元有三种尺寸的面向,

尺寸规则 说明
normal 如果 Grid 是被替换的元件(replaced element),那麽这个 Grid 单元将会依据自然尺寸(natural size)来显示。若该单元有定义尺寸,则使用定义尺寸,若都没有,则使用 stretch 当作 Grid 单元尺寸。
stretch 预设当作 Grid 单元尺寸,会填满整个 Grid 格线系统可使用空间。但,若同轴向有其他 Grid 单元指定了尺寸,会破坏原本 Grid 填满的比例。
其他 使用 fit-content 当作预设尺寸。

何谓 自然尺寸?举例来说,你这个单元是 <img> 元件的话,这个元件尺寸将会被定义为 src 属性所指定的图片尺寸。详细的说明可以看看 w3c 的叙述 CSS Images Module Level 3, natural size

Grid 单元定义尺寸的方式,是使用对齐样式来做设定。对,讲来讲去都会回到对齐模组这件事情,我也是觉得很神奇。

Self-Alignment: Aligning the Box Within Its Parent

基本上单元可以使用这些设定值来对齐,然後只有 stretch 跟尺寸有关,

样式 可用值 预设值
justify-self auto, normal, stretch, <baseline-position> <overflow-position>?, [ <self-position>, left, right ] auto
align-self auto, normal, stretch, <baseline-position>, <overflow-position>? <self-position> auto
place-self <'align-self'> <'justify-self'>? auto

说在前面的,关於 auto, normal, stretch 基本上在没有任何设定的情况,也不是被替换元件的话,基本上没有差异。以下稍微说明一下各种设定数值的作法,

  • auto 基本上跟着 Grid 容器的设定,对应的数值就是 justify-items, align-itemsplace-items 这三个。
  • normalauto 基本上一样,但为何要分两个?老实说我不知道。
  • stretch 依照 Grid 网格格线比例填满,但 margin 任何一个轴方向都不可为 auto,且还是会受到 min-width, min-height, max-width, max-heigth 限制。
  • <baseline-position> 可以使用 baseline, first baseline, last baseline 三种关键字。
  • <overflow-position> 可以使用 safe, unsafe 关键字。
  • <self-position> 可以使用 center, start, end, self-start, self-end 关键字。

可替换元件的尺寸

图片就是一个很常见的可替换元件,

.grid-containter {
    display: grid;
    
    grid-template: repeat(3, 300px) / repeat(3, 300px);
    
    gap: 10px;
}

.grid-item:first-child {
    // 不做任何设定
}
<div class="grid-container">

    <img class="grid-item" src="..." alt="我是图片">
    
    <div class="grid-item">2</div>
    <div class="grid-item">3</div>

    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>

    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>

</div>

最终你会得到这个画面,

https://ithelp.ithome.com.tw/upload/images/20210916/20001433nwupKPdOcC.png

当你把 <img> 设定尺寸後,基本上他就会变成 有定义尺寸 的区块元件。但是呢,区块单元的尺寸跟你所定义的轨道尺寸基本上是两件事情,所以无论他是自然尺寸,还是有定义尺寸,该超出轨道的地方一样都会超出去。

换句话说,除非上述的例子,你的 <img> 使用了 width: 100% 这种相对尺寸,这个时候才会填满整个栏轨道(宽度的部分),但是,因为自然尺寸比例的关系,这种时候就会换列轨道超出范围了。

所以,并不太建议将 Grid 单元使用可替换元件,尺寸的问题你可能会一直处於无解的状况。


无尺寸限制方向的魔性

一般来说无尺寸设定在目前的装置上,是指 row 方向,也就是 grid-template-rows 的样式设定。为何说他有魔性呢?我们举个例子来说,首先,我们先给来一个空的 Grid 容器,

.grid-containter {
    display: grid;
    
    grid-template: repeat(3, 1fr) / repeat(3, 1fr);
    
    gap: 10px;
}
<div class="grid-container">

    <div class="grid-item">1</div>
    <div class="grid-item">2</div>
    <div class="grid-item">3</div>

    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>

    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>

</div>

这个时候你会得到像是这样的结果,

https://ithelp.ithome.com.tw/upload/images/20210916/20001433Wx2IIqH3zu.png

接下来,我们把 5 号的 Grid 容器指定一个 高度 的尺寸,

.grid-item:nth-of-type(5) {
    height: 200px;
}

根据常识判断,我们这个 3x3 的容器,应该会变成第二列的高度为 200px,然後其他列的尺寸应该会保持原本的 fit-content 的相关尺寸,对吧?

对吧?

不对!

https://ithelp.ithome.com.tw/upload/images/20210916/200014333PpJEDDD7o.png

为什麽?

根据官方轨道尺寸演算法 Track Sizing Algorithm 当中的第四点,

Expand Flexible Tracks

当你的剩余空间是无定义长度,换句话说以 row 的角度来看,他可以是 无限大 的情况下,必须根据以下法则来计算尺寸,

  • 根据弹性系数 fr 来均分所有的轨道尺寸。
  • 根据每个 Grid 单元所贡献的最大尺寸(max-content),来计算填充空间,用以当作 fr 的尺寸。

所以,我们把 5 号的 Grid 容器指定一个 高度200px 的话,那麽 Grid 单元当中的最大贡献尺寸就是 200px,所以对於 grid-template-rows 来说,他的 max-content 就会被当作 1fr 来使用。


对齐的基本操作

我们先撇除那些对於会超出 Grid 轨道尺寸的东西,来讲讲 Grid 单元对齐这件事情。虽然我还是觉得,把 stretch 放在对齐模组里面实在是很奇怪,但好多年来都这样了好像也不能怎麽样(笑)。

先决条件,请不要把 margin 的任何方向设定为 auto

首先,我们从空的容器来看,

.grid-containter {
    display: grid;
    
    grid-template: repeat(3, 400px) / repeat(3, 400px);
    
    gap: 10px;
}
<div class="grid-container">

    <div class="grid-item">1</div>
    <div class="grid-item">2</div>
    <div class="grid-item">3</div>

    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>

    <div class="grid-item">7</div>
    <div class="grid-item">8</div>
    <div class="grid-item">9</div>

</div>

接着我们一样把第 5 号的 Grid 单元作一些设定,

.grid-item:nth-of-type(5) {
    align-self: end;
    justify-self: end;
}

那麽我们就会得到这样的结果,

https://ithelp.ithome.com.tw/upload/images/20210916/20001433N4kjlw1DDu.png

你会发现我指定了 Grid 单元的尺寸,然後再把他做一个对齐的动作。这个时候聪明的你应该就会发现,其实 Grid 单元跟整个 Grid 轨道根本没有什麽太大的关系。

是的,Grid 轨道是轨道,Grid 单元是单元,没有直接的关系。

这也就是为什麽 Grid 单元尺寸超出轨道限制时,他就是很单纯的 超过轨道 了,而不会发生任何奇怪的事情的原因。

底下我们用一个简单的示意图来解释上面一堆关键字,

https://ithelp.ithome.com.tw/upload/images/20210916/20001433usaWCnGrmv.png

在这些关键字当中,self-* 的关键字主要会跟 writing mode 有关。由於我们平常所面对的系统都是 LTR(由左至右书写),所以当你遇到 RTL 的文本时,你使用 startself-start 就会出现差异。

我们可以用 direction: rtl 来模拟这种状况,

https://ithelp.ithome.com.tw/upload/images/20210916/20001433HpIFFYWrpA.png

所以对於直式书写的设定也是一样的道理。这个就是对於 Grid 单元的对齐方式,这边之所以不提 stretch 的原因是,他本身就是将整个 Grid 单元填满轨道,所以既然已经 填满轨道 了,那麽就没有对齐的问题。


小记

只要记得一件事情,

除了 stretch 以外,Grid 轨道尺寸不等於 Grid 单元尺寸。

剩下的我们明天再继续。


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


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


<<:  Day 03:如何分析演算法?

>>:  [FGL] 服务简单收 - IMPORT 3 利用http与XML套件取 Web资源

伸缩自如的Flask [day 7] Post data with Form tag

可以先把下面的范例载下来,并执行app.py: https://github.com/wilsons...

Day 07 - 智慧城市Go Smart Award 经历(1) - 初赛

图片来源 今天开始来分享在开赛前几篇的目标设定中Q1设定中一直提到的Go Smart Award,...

Day14 用python写UI-聊聊Scale

今天迈入第14天了,耶~~~今天的内容我也是很喜欢,尤其是自己调整背景颜色的实作,真的觉得非常有趣~...

Security 组别

Security https://wolkesau.medium.com/security-b198...

30天学会 Python-Day22: 自动化的偷吃步

PyAutoGUI 一个可以用来控制键盘和滑鼠的套件 键盘控制 press(key) 按下再放开某键...