點燈坊

學而時習之,不亦悅乎

深入探討 Vuetify 之 v-flex

Sam Xiao's Avatar 2019-07-10

Vuetify 之 Grid System 讓我們不必使用 CSS,只要利用 <v-containr><v-layout><v-flex> 就能 RWD,但 <v-flex> 到底有什麼黑魔法 ?

Version

macOS Mojave 10.14.5
Node 12.4.0
Vue CLI 3.8.4
Vue 2.6.10
Vuetify 1.5.5
CSS 3
Chrome 75.0.3770.100

Vue File

App.vue

<template>
  <v-container fluid class="box">
    <v-layout>
      <v-flex xs4 class="item0">
        <h1>1</h1>
      </v-flex>
      <v-flex xs4 class="item1">
        <h1>2</h1>
      </v-flex>
      <v-flex xs4 class="item2">
        <h1>3</h1>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style scoped>
.box {
  background: #d3d3d3;
}

.item0 {
  background: #faa;
}

.item1 {
  background: #afa;
}

.item2 {
  background: #aff;
}
</style>

<v-container> 下有 3 個 <v-flex>

Flexbox

我們知道 Flexbox 最核心的三個概念是 flex-growflex-shrinkflex-basis,將從這三個概念來理解 <v-flex>

Breakpoint

v-flex000

3 個 <v-flex> 平分 <v-container>

<v-flex xs4 class="item0">
  <h1>1</h1>
</v-flex>

Vuetify 不需使用 flex-basis 指定 item 寬度,取而代之是 grid system 的 breakpoint,如 xs4 props。

v-flex001

Vuetify 提供了 5 個 breakpoint。

v-flex002

<v-flex> 相當於:

flex: 1 1 auto;

也就是

flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

因為 flex-growflex-shrink 皆設為 1,所以無論 item 寬度總和小於 container,或大於 container,item 皆等比例瓜分或縮減,這是最安全方式。

此外,<v-flex> 還自帶 max-width: 100%,但已經被 override 掉。

v-flex003

flex-basis: autoflex-basis: 33.33% 所 override,這也是為什麼 Vuetify 從來都不需使用 flex-basis 原因,完全由 breakpoint 取代。

此外,xs4 還定義了 max-width: 33.33%,override 了 <v-flex> 所定義的 max-width: 100%

最後一個重點,xs4 props 將 flex-grow 重新設定為 0,這也使得寬度固定為 flex-basismax-width,不受 container 剩餘寬度影響。

No Breakpoint

<v-container fluid class="box">
  <v-layout>
    <v-flex class="item0">
      <h1>1</h1>
    </v-flex>
  <v-flex class="item1">
    <h1>2</h1>
      </v-flex>
    <v-flex class="item2">
      <h1>3</h1>
    </v-flex>
  </v-layout>
</v-container>

<v-flex> 完全不寫 xs4 props 呢 ?

v-flex007

結果依然為等寬。

v-flex008

<v-flex> 定義了 flex: 1 1 automax-width: 100%,由於沒有定義 width,相當於 width: auto,由 browser 自行決定寬度,但因為 flex-grow1,最後又均分所有 container 剩餘寬度。

也就是若要均分 container,可以不必使用 breakpoint 指定寬度,因為 <v-flex> 自帶 flex-grow: 1

<v-container fluid class="box">
  <v-layout>
    <v-flex xs8 class="item0">
      <h1>1</h1>
    </v-flex>
    <v-flex class="item1">
      <h1>2</h1>
    </v-flex>
    <v-flex class="item2">
      <h1>3</h1>
    </v-flex>
  </v-layout>
</v-container>

若有些 <v-flex> 指定 breakpoint,有些 <v-flex> 不指定呢 ?

v-flex009

有指定 breakpoint 的 item 依其寬度顯示,沒指定的 item 均分 container 剩餘寬度。

v-flex010

指定 xs8 pros 的 item,其 max-width: 100% 已經被 override。

v-flex011

xs8 props 的 flex-basis: 66.66%max-width: 66.66% override 了,因此其寬度為 66.66%,且其 flex-grow0 也 overrider <v-flex> 預設的 1,也就是不受 container 剩餘寬度影響。

v-flex012

至於沒指定 breakpoint 的 item,max-width: 100% 沒被 override, flex 也沒被改為 0,因此其寬度會自動平分 container 剩餘寬度,因此等寬。

<v-flex> 部分使用 breakpoint 指定寬度,部分沒有,則有指定 breakpoint 的 <v-flex> 將依 user 指定寬度顯示,沒指定者皆平分 container 剩餘寬度等寬

Grow & Shrink

v-flex004

1 會瓜分 container 剩餘寬度,而 23 僅與內文同寬。

<v-container fluid class="box">
  <v-layout>
    <v-flex grow class="item0">
      <h1>1</h1>
    </v-flex>
    <v-flex shrink class="item1">
      <h1>2</h1>
    </v-flex>
    <v-flex shrink class="item2">
      <h1>3</h1>
    </v-flex>
  </v-layout>
</v-container>

第 3 行

<v-flex grow class="item0">
  <h1>1</h1>
</v-flex>

<v-flex> 使用了 grow props,表示將瓜分 <v-container> 剩餘寬度。

第 6 行

<v-flex shrink class="item1">
  <h1>2</h1>
</v-flex>

<v-flex> 使用了 shrink props,表示其寬度與內文同寬。

v-flex005

grow 相當於 CSS 的 flex-grow: 1

v-flex006

shrink 相當於 CSS 的 flex-grow: 0

因此 1 : 0 : 0,container 剩餘寬度全部被 item 0 瓜分。

Conclusion

  • Vuetify 不需使用 flex-basis,完全由 breakpoint 取代
  • <v-flex> 不指定 breakpoint,則平分 container 剩餘寬度
  • Vuetify 的 growshrink 與 CSS 的 flex-growflex-shrink 不太一樣;grow 相當於 flox-grow: 1,而 shrink 相當於 flex-grow: 0
  • 了解 grid system 與 flexbox 原理後,其實 grid system 就不再那麼黑魔法

Reference

Vuetify, Grid system
Vuetify, Breakpoints