簡單介紹

雖然說 Flexbox 已經推出好一段時間了,但說實在話我自己好像沒有特別著墨。當然,我覺得如果可以的話,去看一下 Amos 的課程,一定比看我在這邊講幹話來得實際!

首先,我們先理解一下 flex 的作法,

.flexbox {
    display: flex;
}

首先是把一個 DOM 元件定義成 flex,這樣接下來的設計才會生效。這個 flex 元件預設會使用 row 這個維度來顯示資料。換句話說,你若什麼都不寫的話,他的 flex-flow 預設就會是 row nowrap 這樣的設定,

.flexbox {
    display: flex;
    flex-flow: row nowrap;
}

如果我們有一個 HTML 長這樣,

<main>
    <section class="flexbox">
        <h1 class="slogan">Hello World</h1>
        <h4 class="description">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sed eleifend dui. Ut ac justo eu orci hendrerit tempus.</h4>
        <picture class="picture">
            <source srcset="./static/hero.avif,
                ./static/[email protected] 2x,
                ./static/[email protected] 3x">
            <source srcset="./static/hero.webp,
                ./static/[email protected] 2x,
                ./static/[email protected] 3x">
            <img srcset="./static/hero.png,
                ./static/[email protected] 2x,
                ./static/[email protected] 3x"
                src="./static/hero.png"
                alt="Hello World">
        </picture>
    </section>
</main>

那麼你會發現三個元素都擠在一起,而且會超出畫面。

這個時候你想說,我在 .flexbox 加上寬度限制應該就可以了吧?

.flexbox {
    display: flex;
    width: 100%;
}

這樣沒用喔~

如果加上 overflow: hidden 呢?他就會變成畫面被切掉的樣子。

那我要平均一下,這樣我可以在裡面的元件使用如下的設定,

.slogan, .description, .picture {
    flex: 0 1 33.33%;
}

你以為圖片會縮小嗎?這樣沒用喔~

接著你必須針對圖片的最大寬度做設定,

.picture img {
    max-width: 100%;
}

最終會呈現的樣子是這樣,

好的,現在來說明一下這樣的設定最終會影響到的地方,

  • flex 是語法糖,三個數值分別為 flex-grow, flex-shrink, flex-basis
  • 上述三個預設值分別為 0, 1, auto,翻成中文就是不分配剩餘空間,空間不足可壓縮,自動指定寬度。
  • .slogan, .description, .picture 會被定義成 display: block; 的元件。
  • 在裡面用 float 是無效的。
  • 在裡面用 position: absolute, position: fixed 請左轉離開謝謝。

所以如果我想要圖片比較大,

.slogan, .description, .picture {
    flex: 0 1 33.33%;
}
.picture {
    flex: 1 0 auto;
}

這樣你的圖片就會填滿所分配到的空間。但,請切記,這個時候 flex-basis 所分配的空間就不會是原本的 33.33% 了。然後,你會發現你的圖片又超出畫面的範圍了。

所以,在這個時候你需要把 flex-shrink 設定為 1,這樣你的圖片才不會被切掉。

好了,這邊就有幾個癥結點需要留意,

  • flex-basis 會覆蓋原有的 width 設定(包含 auto)。
  • flex-growflex-basis 同時設定,後者會被覆蓋寬度效果。
  • flex-grow 若為 0flex-basis 會恢復效果。
  • flex-sharink 若為 0flex-basis 若為 auto,內容會撐滿整個元件(甚至溢出容器)。

你的外層容器若為相對寬度,且為不斷行(nowrap),則請留意以下狀況,

  • flex-basis 設定為絕對數值(例如 600px)無效果。
  • flex-basis 若有值,flex-grow 設定 1 以上無效。
  • flex-basis 若無值,flex-sharink 設定 1 以上無效。
  • flex-basis 總和大於外層容器,flex-sharink 數值越大,縮小幅度越多。

以上各種情況,希望大家不會遇到。


行與列

剛剛提到的都是以「列」的方式來呈現,當然 flex 也可以使用「行」的方式呈現,

.flexbox {
    display: flex;
    flex-flow: column nowrap;
}

這樣的使用情境並不多,由於我們習慣了多欄方式來排列畫面,所以使用列來排列的地方就不是那麼廣泛。通常,會使用這種方式排列,以整個網站結構來看,天地之間講幹話就是,

<body>
    <header><!-- 天 --></header>
    <main><!-- 講幹話 --></main>
    <footer><!-- 地 --></footer>
</body>

如果我們把 <body> 當作是一個最大的 flex 容器來看,裡面的 <header>, <main><footer> 就是「行」排序的方式。

請不要真的把 <body> 設定為 flex

然而,關於 column 這件事情,大抵上跟 row 沒有太多差異,唯一比較不一樣的地方,在於 wrap 這件事情上。

可以參考我 比較近期 的幹話文章。

實際使用上,他對於卡片式的排版還是有所幫助的,只要你的卡片高度固定,這個排版方式使用起來會比較方便。


那個斷點

客戶說我這個斷行是看過八字的。

首先,如果你在 flex-wrap 設定了 wrap 或是 wrap-reverse 的話,當寬度不足的時候,就會出現斷點。最簡單的例子就是,

.slogan, .description, .picture {
    flex: 1 0 50%;
}

然後 .picture 就一定會被中斷放到下一列。換句話說,就是當 flex-basis 填滿了容器的寬度的時候,如果有發生「不足」的情況,就會將「下一個」元件給斷行。然而,這個斷行的設定,會干擾到某些東西,當你的容器使用相對寬度的時候,會發生這些事情,

  • flex-sharink 在斷行設定下無效果。
  • flex-basis 若在一行內「未填滿」,則 flex-grow 會影響元件相對寬度。
  • 若元件的 flex-basis 相加剛好填滿一行,則 flex-grow 無效果。
  • 「被斷行」的元件若 flex-grow 大於等於 1,會無視 flex-basis 填滿容器。

我個人是覺得,應該不會有人會著墨在 flex 這件事情上打轉,頂多就是打開 Bootstrap 4,然後套上去,有人關心過 flex 的感受嗎?

沒有。

歐,對了,這一招可以強迫斷行,不要問我為什麼我會生氣!

flex-basis: 100%;

另外,當你使用 flex-direction: column 的時候,這個 flex-wrap 基本上是無效的。同樣可以參考我 比較近期 的幹話文章。


教練我想要對齊

通常來說,我們會很在意的地方應該是「垂直置中」對齊。這一點在 flex 裡面很容易實現,你只需要 align-items: center; 就收工了。

然後你會發現,在沒有特定高度的情況下會失效。

師父有交代,收工之前不能罵髒話。

關於對齊這件事情,Amos 寫了 23 種,我這邊就不野人獻曝了。