iT邦幫忙

2021 iThome 鐵人賽

DAY 3
1
Modern Web

CSS Flex/Grid Layout Modules系列 第 3 篇

[CSS] Flex/Grid Layout Modules, part 3

  • 分享至 

  • xImage
  •  

結果我真的兩篇就快講完了(驚恐)。

既然是說要講切版的話,還是多少交代一些比較基礎的東西好了。

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 元件內的話,那麼使用 margin 或 padding 的差異就不大。另外,有些狀況使用 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 會與部分樣式有權重問題,

  • margin 與 justify-content, align-items 會產生疊加效應。
  • auto 關鍵字會覆蓋部分 justify-content 與 align-items 的設定。
  • margin 使用數值在一定條件(大於剩餘空間)下,會覆蓋 justify-content 與 align-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-grow 與 flex-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-grow 與 flex-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


上一篇
[CSS] Flex/Grid Layout Modules, part 2
下一篇
[CSS] Flex/Grid Layout Modules, part 4
系列文
CSS Flex/Grid Layout Modules 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言