[CSS] Flex/Grid Layout Modules, part 3

结果我真的两篇就快讲完了(惊恐)。

既然是说要讲切版的话,还是多少交代一些比较基础的东西好了。

Flex 的轴流向与留白

之前我们提及了多数 CSS 框架的设计,绝大部分都是 row 的主要轴流向。原因也相对单纯,基本上你不太会拥有一个「无限宽度」的装置,所以在目前主流装置下,我们的宽度都会存在一个极大值,这个极大值基本上就会是整个 Flex 容器的主要轴尺寸。

所以,我们以双栏结构来看,最单纯的设定就会像是这样,

.flex-container {
    display: flex;
    flex-flow: row wrap;
    align-items: flex-start;
    justify-content: flex-start;
}

接着,由於我们需要「双栏」的设计,所以我们的元件定义就是,

.flex-item {
    // 通用设定放这边
    margin: 0 10px;
}

.flex-aside {
    // 侧边区块,我们预设把他放在左边
    flex: 1 0 20%;
    max-width: calc(20% - 20px);
}

.flex-main {
    // 主要内容区块,我们把他放在右边
    flex: 1 0 80%;
    max-width: calc(80% - 10px);
    
    // 取消左边留白,让我们的间隔看起来相同
    margin-left: 0;
}

最终我们会获得这样的结果,

https://ithelp.ithome.com.tw/upload/images/20210906/20001433BSebonOATO.png

可是你不是说不要用 margin 来定义间隔(gap)吗?

是的,我们在这边也可以使用 padding 来制作我们间隔,但是,当你的 Flex 容器或是元件有使用背景设定时(background),你还是得使用 margin 来当作间隔会比较适当。因为 background 会包含 padding 的留白部分,所以对於 Flex 元件来说,使用 margin 会比较适当。

当然,如果你使用背景的区块是在 Flex 元件内的话,那麽使用 marginpadding 的差异就不大。另外,有些状况使用 margin 是必须特别留意的,

  1. 当你有使用 stretch 的时候。
  2. 当你的 margin 有需要使用 auto 的时候。

对於 Flex 元件来说,margin 的关键字 auto 有一个特殊的效果,就是 自动补白 的特性。举例来说,我们刚刚的主要栏位如果这样设定,

.flex-main {
    margin-left: auto;
}

那麽他就会将 剩余空间 往左边补白。请留意,这里的剩余空间是指容器本身的剩余空间。由於我们使用了计算过後的 max-width 会将整个 Flex 容器填满。在没有填满,且没有设定 flex-grow: 1 的情况下,这个自动补白才会生效。

https://ithelp.ithome.com.tw/upload/images/20210906/20001433ZkHpOYv3xc.png

自动补白看起来好像很好用,不过,margin 会与部分样式有权重问题,

  • marginjustify-content, align-items 会产生叠加效应。
  • auto 关键字会覆盖部分 justify-contentalign-items 的设定。
  • margin 使用数值在一定条件(大於剩余空间)下,会覆盖 justify-contentalign-items 的设定。

只要是跟 剩余空间 有关的部分都会受到影响。

https://ithelp.ithome.com.tw/upload/images/20210906/20001433kk2elkj0aM.png

https://ithelp.ithome.com.tw/upload/images/20210906/20001433UTHWsGNqiL.png

请留意,无论是叠加还是干涉样式设定,其本身的样式还是有效的,以上述的例子来说,

.flex-main {
    align-self: center;
    margin-top: auto;
}

虽然最终呈现的状态并非 align-self: center 的结果,但其自身还是受到 align-self: center 的样式所规范。而左边的 align-self: stretch; 也是一样的道理。

另外,也会影响这个结果的则是 flex-growflex-shrink 这两个样式设定。我们先前有提到 flex-grow 是做一个 填充 的动作,所以,当你在没有指定 Flex 元件的 轴方向 尺寸时,他会将轴方向作填满动作。

换句话说,这个填满跟 margin 的样式权重,由大到小排列会是这样,

  • margin 数值尺寸,例如 margin-left: 200px
  • flex-grow
  • flex-basis || width || max-width || height || max-height
  • margin 的关键字 auto

而如果是 flex-shrink 的话,就比较特殊了,由於他是 压缩,所以在我们使用 margin 的情况下,并不会 触发 压缩这件事情,只有当 Flex 容器空间不足够时才会触发,且他也同样会干扰压缩的情况。

  • margin 数值尺寸,例如 margin-left: 200px
  • flex-shrink
  • flex-basis || width || min-width || height || min-height
  • margin 的关键字 auto

其顺序上跟 flex-grow 雷同,但他的先决条件是 Flex 容器空间不足 的情况下才会发生。


Flexbox 巢状结构

基本上应用的方式与一般 Flex 容器没有差异,就是单纯的把 Flex 元件再次指定为 Flex 容器,在使用上没有太大的区别。不过你得留意的是,原有区块元件的父子元件同方向 margin 合并问题在巢状结构中并不会发生。

也就是说,Flex 元件与容器会独立拥有各自的 margin,若 Box 元件没有设定 overflow 的情况下,

.box-module-parent {
    margin-top: 30px;
}
.box-module-child {
    margin-top: 10px;
}

上述两者因为同方向 margin 的关系,会产生合并(collapse),

https://ithelp.ithome.com.tw/upload/images/20210906/200014333hzAQKOdrV.png

而这件事情在 Flex 容器中不会发生,

.flex-module-parent {
    margin-top: 30px;
}
.flex-module-child {
    margin-top: 10px;
}

https://ithelp.ithome.com.tw/upload/images/20210906/20001433ueKNuVNEIV.png

当然,你在一般 Flex 容器遇到的 margin 状况,在这种情况下也免不了。所以,基本上多层次的运用 Flexbox 也不会有太多的意外,该写的意外我应该都写的八九成了。

Flexbox 终究还是拿来画出框架的。

其实总的来说,这跟你用许多 CSS 框架的方式是雷同的,若是以 Bootstrap 为例子,其实就类似於,

<div class="conatiner">
    <div class="row">
        <div class="col-4">
        </div>
        <div class="col-8">
            <div class="row">
                <div class="col-6">
                </div>
                <div class="col-6">
                </div>
            </div>
        </div>
    </div>
</div>

这就端看你要怎麽去规划你的框架该长成什麽样子,只是在不使用 CSS 框架的情况下,你的 HTML 可以稍微简洁一点点。当然,那种写到烂掉的也不是没有。


关於对齐

其实比较让人觉得有趣的,大概就是置中对齐这件事情。

当然讲到置中对齐,就得呼叫一下 Amos CSS垂直置中技巧,我只会23个,你会几个

我只会一种,就是 align-items: center; 这样。

说到对齐,就得提到 CSS 关於对齐的模组 CSS Box Alignment Module Level 3,但这边不会提到太多,我们就单纯的拿 Flexbox 可以使用的部分出来聊聊。

样式 应用范围 适用状态
justify-content Flex 容器 主要轴方向
align-content Flex 容器 交叉轴方向,多行状态
align-items Flex 容器 主要轴方向
align-self Flex 元件 多行状态

请注意有两个样式是必须要有 多行状态 才会有效果。当然,说到对齐就必须得提到先前说过的 flex-growflex-shrink 这两个样式设定。在我们没有特别指定主要轴、交叉轴尺寸,或是特别指定 Flex 元件尺寸的情况下,这两个设定在某些情况下会让你产生 客户说没对齐 的情况。

什麽叫做 客户说没对齐

https://ithelp.ithome.com.tw/upload/images/20210906/2000143345eFc0V1UG.png

逻辑上来说,这是对齐的,但如果需要「根据底边置中对齐」的时候,他就不符合预期结果。当然,请不要传这一篇去给客户看谢谢。 身为一个专业的前端工程师,这样的问题也不是没有解法。

你就把两个元件锁定相同高度就好(卍解)。

我在 Flexbox 最後面会解释关於 Flex 的一些演算方式,这边就暂不赘述。这样的问题其实很常发生,当你的 Flex 容器允许断行,在产生多行的情况下,由於整个容器的交叉轴尺寸是未知的(也就是随内容动态增长),所以元件尺寸就会因为邻近元件的关系而造成对齐点的问题。

以往我们使用区块元件,利用 float: left; 大多会有这种状况,

https://ithelp.ithome.com.tw/upload/images/20210906/20001433RRnJGdgvDS.png

虽然 Flex 容器没有 靠左对齐 的特性,但,

https://ithelp.ithome.com.tw/upload/images/20210906/20001433N6qPLygvWu.png

虽然没有了奇怪的对齐点,但这就是所谓的有一好没两好。这一点在 Grid Layout Module 里面会更明显。所以,为了解决这种奇怪的补白问题,在一些必要情况下,请赋予你的 Flex 元件一个交叉轴尺寸,用以确保你在 flex-wrap: wrap; 的情况下会是比较好的呈现结果。

以下我直接用图片来解释各种 对齐

https://ithelp.ithome.com.tw/upload/images/20210906/20001433B7bDKLyVin.png

附带一题,最後的 space-evenly 是属於对齐模组草稿阶段,但浏览器支援度也是不错。在 Caniuse 里面有 95% 以上的支持度。

CSS Box Alignment Module Level 3, Editor's Draft

space-evenly, caniuse.com

另外一个就是交叉轴的对齐(stretch 不算但我还是列出来),

https://ithelp.ithome.com.tw/upload/images/20210906/20001433tsUkHexDsb.png


小记

基本会遇到的状况在这边大概可以涵盖个七八成,所以这个时候你再回头去看看那些知名 CSS 框架,应该就可以理解人家为什麽要这样做。

下一次会提及一些关於 Media Query 的事情来聊聊 Flexbox 的使用情境。


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


部落格同步放送:

[CSS] Flex/Grid Layout Modules, part 3


<<:  DAY08 资料前处理-缺失值处理方法

>>:  Day2 线性回归(Linear Regression)

[神经机器翻译理论与实作] 重新检视有无注意力机制的Encoder-Decoder

前言 今天是个美丽的错误,本来预计将昨日写好的 Encoder 、Decoder 、 LuongAt...

Day-02 请解释 Ruby 和 Rails 是什麽?

首先要注意 Ruby 和 Rails 是不一样的东西! Ruby 是一种物件导向的程序语言,而 R...

序幕

Kotlin程序设计这门课相当热门,归功於科技界巨擘Google的推广和能够多平台执行的设计,一个可...

Day 05 依赖注入(Dependency Injection)

问题来了,为什麽Blazor会知道WeatherForecastService在这里可以调用? da...

电子书阅读器上的浏览器 [Day22] 翻译功能 (IV) 内容分页

将网页原文分页翻译 大致上的实作,到上一篇就差不多了。但是在使用几天後发现一个问题,如果文章内容太长...