Vuetify3 のレイアウトに関するメモ


このページは、下記に順次移行中です。

- [Vuetify3 の基本](https://zenn.dev/bbled/books/vuetify3_book)

Vuetify3 のメモです。2 と違う点も多いので注意。Vuetify 3.3.18 で動作を確認しています。

# 関連記事

- [Vuetify3 のレイアウトに関するメモ（この記事）](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)
- [Vuetify3 でよく使うコンポーネントのメモ（１）](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203)
- [Vuetify3 でよく使うコンポーネントのメモ（２）](https://qiita.com/mml/items/16030c4404b4a814956b)
- Vuetify3 Labs
-- [DatePicker](https://qiita.com/mml/items/2c99fa3fcfebd4979bc3)
-- [DataTable](https://qiita.com/mml/items/ae334f79f14469efccf0)

# Vuetify3 のプロジェクト作成


Vuetify3 stable になって、下記コマンド一発でいけるようになりました。

```
$ yarn create vuetify
```

詳しくは、下記をどうぞ。

- [Vuetify3 Installation](https://next.vuetifyjs.com/en/getting-started/installation/)

Nuxt3 の場合は、下記を見てください。

- [Nuxt3 で Vuetify3 を使う](https://qiita.com/mml/items/9936471c551ee3f15218)

Vue-Router を使って初期化した場合は、`App.vue` の書き方のデフォルトが従来（Vue2) と少し変わっています（別記事の予定）。

# アプリケーションの基本レイアウト

## 典型的なデザイン

- [デフォルトのアプリケーションマークアップ](https://vuetifyjs.com/ja/components/application/)

上記で説明されている、典型的なデザインで画面をつくると下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f7b7ba5a-c4f0-535c-8302-5bab69996343.png)

コードは下記です。

```App.vue
<template>
  <v-app>
    <v-system-bar color="secondary">
      System Bar
    </v-system-bar>

    <v-app-bar color="primary">
      <v-app-bar-title>
        Application Bar
      </v-app-bar-title>
    </v-app-bar>

    <v-navigation-drawer permanent>
      Navigation Drawer
    </v-navigation-drawer>

    <v-main>
      <v-container>
        Main Contents
      </v-container>
    </v-main>

    <v-bottom-navigation>
      Button Navigation
    </v-bottom-navigation>

    <v-footer color="primary" app>
      Footer
    </v-footer>

  </v-app>
</template>
```

## Application (v-app)

コード

```App.vue
<template>
  <v-app>
    contents
  </v-app>
</template>
```

結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f8b43f7e-1320-a7cb-a05f-4baac2f5d251.png)

基本、Vuetify3 では `<v-app>` の内側に要素を置きます。`<v-app>` の外側に置かれた要素は、レイアウトの自動管理が行われません。要素同士が重なってしまったり、正常に表示されないことがあります。また `<v-app-bar>` のように、`<v-app>` 内に置かなければ、そもそも正常にレンダリングされない要素もあります。

公式のドキュメントによれば、`<v-ap>` はひとつのアプリにひとつまで、なおかつすべての vuetify のコンポーネントを含むように配置する必要があるそうです。また、`light` のようなテーマの指定が反映されるのは `<v-app>` を使った場合のみです。

逆に言えば、自動レイアウトやテーマの反映を必要としない場合は、必ずしも `<v-app>` を配置する必要はありません。

なお、ブラウザでコードを見ると `v-app` は自動的に `class="v-application v-layout"` に変換されているようです。なので、`v-layout` でも部分的に代用できます。

```App.vue
<template>
<v-sheet>
  <v-layout>
    <v-app-bar color="primary">
      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>
    <v-main>
       Main Contents
    </v-main>
  </v-layout>
</v-sheet>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e83956a7-ddab-8c23-02df-2cbe6a22b706.png)

これでも一応うまくいきます。(`<v-app-bar>` と `<v-main>` は  `<v-layout>` か `<v-app>` の内側に置かなければならない）

でも `<v-app>` を使っておけば、問題なくどのコンポーネントも使えるしテーマも反映されるので、特段の理由がなければ `<v-app>` を使っておけばいいんじゃないかなあ（適当）。

## Application Bar （v-app-bar）

- [ApplicationBar](https://next.vuetifyjs.com/en/components/app-bars/) (公式)

コード

```App.vue
<template>
  <v-app>
    <v-app-bar>
      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>
```

結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b4e31de1-38db-c15f-9321-1cc3816bd4a0.png)

アプリケーションバーは、画面の上部を横断するように配置されます。このアプリケーションバーは、サイト内でページを遷移しても、同じバーが表示され続けるようになっていることが多いです。

アプリケーションバーには、ボタンやメニューを配置できます。配置方法については後述します。

コード：

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <template v-slot:prepend>
          <v-app-bar-nav-icon></v-app-bar-nav-icon>
      </template>

      <v-app-bar-title>
        Application
      </v-app-bar-title>

      <template v-slot:append>
        <v-btn>
          Sign-In
        </v-btn>

        <v-btn>
          <v-icon>
            mdi-home
          </v-icon>
        </v-btn>
      </template>
      
    </v-app-bar>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/205169f6-86e6-2b8c-bde9-7b4bffc17710.png)


Vuetify3 からは `<v-btn>` などは `<template v-slot:append>` の中に書くことになったようです。`<app-bar-title>` より左に配置するものは、`<template v-slot:prepend>` に置きます。

ちなみに、上のコードでは `<template v-slot:prepend>` や `<template v-slot:append>` を外しても特に動作は変わりません。`v-slot` を使って記述すると、タグの記述の順序に関係なく、決められた位置（prepend ならタイトルより左、append ならタイトルより右）に必ず配置してくれる、ということのようです。

```app.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <template v-slot:append>
        <v-btn>
          Sign-In
        </v-btn>

        <v-btn>
          <v-icon>
            mdi-home
          </v-icon>
        </v-btn>
      </template>

      <v-app-bar-title>
        Application
      </v-app-bar-title>

      <template v-slot:prepend>
          <v-app-bar-nav-icon></v-app-bar-nav-icon>
      </template>
      
    </v-app-bar>
  </v-app>
</template>
```

上のように、要素の順序を変えてもタイトルとほかの要素の位置関係は変わりません。`template` を外すと位置が変わります。

```app.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      
        <v-btn>
          Sign-In
        </v-btn>

        <v-btn>
          <v-icon>
            mdi-home
          </v-icon>
        </v-btn>
    
      <v-app-bar-title>
        Application
      </v-app-bar-title>

      <v-app-bar-nav-icon></v-app-bar-nav-icon>
      
    </v-app-bar>
  </v-app>
</template>
```

結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0472d4fe-c1e9-31ce-f892-6be54f15db97.png)

なお、mdi-icons は場合によって `yarn add @mdi/font` が必要です。nuxt3 の場合は下記参照のこと。

- [Nuxt3 で Vuetify3 を使う](https://qiita.com/mml/items/9936471c551ee3f15218)

### Application Bar の拡張

`<template v-slot:extention>` を使うと、アプリケーションバーの下側に行を追加できます。画像の埋め込みも可能です。

```App.vue
<template>
  <v-app>
    <v-app-bar
      image="https://iconape.com/wp-content/files/no/113101/png/vuetify.png"
    >
      <v-app-bar-title>
        Application
      </v-app-bar-title>

      <template v-slot:extension>
        <v-spacer></v-spacer>
          <v-btn>Hoge 1</v-btn>
          <v-btn>Hoge 2</v-btn>
          <v-btn>Hoge 3</v-btn>
        <v-spacer></v-spacer>
      </template>

    </v-app-bar>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c36096fe-6adc-22b0-a94b-c0c4c9fdac9e.png)

## Main Contents （v-main）

コード

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>

    <v-main>
      Main Contents
    </v-main>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ef07aca6-1dc9-063c-7219-542e8675f11a.png)

ページに表示させたいメインコンテンツは、`<v-main>` 内に記述します。`<v-main>` 内に記述することで、アプリケーションバーの下、フッターの上にコンテンツが配置されます。

表示したいコンテンツを `<v-main>` で囲わないと、アプリケーションバーと重なってしまい、うまく表示されません。

コード：

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>
    <p>hoge 1</p>
    <p>hoge 2</p>
    <p>hoge 3</p>
    <p>hoge 4</p>
    <p>hoge 5</p>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/083ffa0e-5ad4-4918-48d6-85aa9637744a.png)

 `<v-main>` で囲わないと、文字列の先頭がアプリケーションバーと重なってしまいます。

コード：

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <v-app-bar-title>
        Application
      </v-app-bar-title>
    </v-app-bar>
    <v-main>
      <p>hoge 1</p>
      <p>hoge 2</p>
      <p>hoge 3</p>
      <p>hoge 4</p>
      <p>hoge 5</p>
    </v-main>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/751d8e3b-4c62-101b-f283-ea14e8f400e8.png)

 `<v-main>` で囲まれた文字列は、アプリケーションバーと重ならないように、自動的に配置されるようになります。

なお `<v-main>` は  `<v-app>` もしくは  `<v-layout>` の内側に配置する必要があります。 一応、`<v-main>` を同じページ内に複数配置することも可能です（お勧めしません）。

## Container （v-container）

 `<v-container>` で囲うことで、内側にある要素をひとまとまりのグループのように扱えます。機能的には `<div>` とほぼ同じですが、デフォルトでマージン、パディング、幅が指定されている点が異なります。

コード：

```App.vue
<template>
<v-app>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>
  <v-main>
    <v-container>
      <p>Hoge 1</p>
      <p>Hoge 2</p>
      <p>Hoge 3</p>
      <p>Hoge 4</p>
      <p>Hoge 5</p>
    </v-container>
    <div>
      <p>Hoge 1</p>
      <p>Hoge 2</p>
      <p>Hoge 3</p>
      <p>Hoge 4</p>
      <p>Hoge 5</p>
    </div>
  </v-main>
</v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/48299f7f-d56a-9519-abcc-0239d7e1690b.png)


`<v-container>` で囲った文字は、周囲に少しスペースが開きます。`<div>` のほうはそれがありません。また `<v-container>` は横幅の最大値が指定されています。ブラウザを横に大きく広げると、文字列が中央寄せで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bcc62340-937a-c114-8b4c-2f5512d8206e.png)

`<v-container>` の幅やスペース（パディング、マージン）は指定することができます。指定方法については、Spacing の項目で説明します。

## Navigation Drawers （v-navigation-drawer）

- [Navigation Drawers](https://next.vuetifyjs.com/en/components/navigation-drawers/)

ページの左側に表示されていることが多い、サイト内を移動するためのメニューみたいなコンポーネントのことです。

```App.vue
<template>
<v-app>
  <v-navigation-drawer
    permanent
  >
    <v-list @click:select="test">
      <v-list-item title="Home" value="home"></v-list-item>
      <v-list-item title="About" value="about"></v-list-item>
    </v-list>
  </v-navigation-drawer>

  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-main>
    <v-container>
      Main Contents
    </v-container>
  </v-main>
</v-app>
</template>
<script>
export default {
  methods: {
    test(arg)
    {
      console.log( "test", arg.id );
    }
  }
}
</script>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/73746a76-f770-fcf5-c89a-3aecc7fd495d.png)

Home をクリックすると、コンソールに home と表示されます。

アプリケーションバーと順序を入れかえると、アプリケーションバーより下に表示されるようになります。

```App.vue
<template>
<v-app>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-navigation-drawer
    permanent
  >
    <v-list>
      <v-list-item title="Home" value="home"></v-list-item>
      <v-list-item title="About" value="about"></v-list-item>
    </v-list>
  </v-navigation-drawer>

  <v-main>
    <v-container>
      Main Contents
    </v-container>
  </v-main>
</v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5425ca47-3f88-be9f-59ef-c4eeceb45631.png)


ボタンを押したときだけメニューを表示したい場合は、`<v-app-bar-nav-icon ` と `v-model` を使って下記のようにします。

```App.vue
<template>
<v-app>
  <v-app-bar color="primary">

    <v-app-bar-nav-icon 
      variant="text"
      @click.stop="drawer = !drawer">
    </v-app-bar-nav-icon>

    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-navigation-drawer
    v-model="drawer"
  >
    <v-list>
      <v-list-item title="Home" value="home"></v-list-item>
      <v-list-item title="About" value="about"></v-list-item>
    </v-list>
  </v-navigation-drawer>

  <v-main>
    <v-container>
      Main Contents
    </v-container>
  </v-main>
</v-app>
</template>
<script>
export default {
  data: () => ({
    drawer: null,
  }),
}
</script>
```

結果：

![vuetify1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c8d0e5af-2e1f-f636-47dc-a37ce02cb1e2.gif)

ボタンを押すことで、メニューを動的に出し入れできるようになります。

`<v-list nav>` として、アイコンの指定もすると、かなり良い感じになります。

```App.vue
  <v-navigation-drawer
    v-model="drawer"
  >
    <v-list nav>
      <v-list-item prepend-icon="mdi-view-dashboard" title="Home" value="home"></v-list-item>
      <v-list-item prepend-icon="mdi-forum" title="About" value="about"></v-list-item>
    </v-list>
  </v-navigation-drawer>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/91457be9-a20c-a113-673f-cbe86b3ee67b.png)

## Footer (v-footer)

- [Footer](https://next.vuetifyjs.com/en/components/footers/)

画面の下のほうに表示される、サイトの情報の提示などに使われるコンポーネントです。

```App.vue
<template>
<v-app>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-main>
    <v-container>
      Main Contents
    </v-container>
  </v-main>

  <v-footer color="primary">
    (c) BBLED
  </v-footer>
</v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/87d966dc-6570-ac34-f483-26d5b2c5d09e.png)

footer はメインコンテンツが終わった位置から、下方向に無限に続く感じで作られます。footer の開始位置を決めたいときは、メインコンテンツ側で高さを指定するしかないようです。

`<v-container>` は高さが指定できないので、内側に `<v-sheet>` を配置しています。

```App.vue
<template>
<v-app>
  <v-app-bar color="primary">
    <v-app-bar-title>
      Application
    </v-app-bar-title>
  </v-app-bar>

  <v-main heidht="50em">
    <v-container>
      <v-sheet min-height="20em">
        Main Contents
      </v-sheet>
    </v-container>
  </v-main>

  <v-footer color="primary">
    2022 (c) BBLED
  </v-footer>
</v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a0f0d6e9-03a7-3b96-be6d-4019bbdeaba5.png)

v-footer は app 属性を付けると、画面下部に固定されます。また、permanent 付きの `v-navigation-drawer` とも重複しなくなります。以前はドキュメントに何の記述もなかったのですが、下記ドキュメントに説明が追加されました。

- [Footer](https://vuetifyjs.com/en/api/v-footer/#props-app)

```App.vue
<template>
  <v-app>

    <v-app-bar color="primary">
      <v-app-bar-title>
        Application Bar
      </v-app-bar-title>
    </v-app-bar>

    <v-main>
      <v-container>
        Main Contants
      </v-container>
    </v-main>


    <v-footer color="primary" app>
      Footer
    </v-footer>

  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5fa29b8c-4c86-e734-c815-91e1b021847b.png)

特に理由がなければ、v-footer に関しては app 属性を指定したほうがよさそうです。

Vuetify2 までは、ボタンが block 要素扱いで、なおかつ `v-footer` の要素の配置がデフォルトで縦方向だったので、横方向にボタンを並べるには `d-flex` を使うか `v-toolbar` を使う必要がありました。しかし 3.0.0 からは両方とも仕様が変更されたようで、単純にボタンを並べるだけで横方向に並ぶようになりました。

```App.vue
<template>
  <v-app>
    <v-main>
      <v-container>
        Main Contents
      </v-container>
    </v-main>
    <v-footer app color="primary">
      <v-btn color="primary" icon="mdi-home"></v-btn>
      <v-btn color="primary" icon="mdi-file"></v-btn>
      <v-btn color="primary" icon="mdi-google"></v-btn>
    </v-footer>
  </v-app>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0936d330-9f13-e60f-95cf-0ab7d0155c28.png)

## コンポーネント間の違い

ページ内にボックス（領域）を確保する要素としては、以下があります。

- span：　改行なしで（inlineで）テキストなどを配置したい時
- div: 副作用なくスペースを取りたい時
- v-container；　装飾なしのちょっとしたスペースを取りたい時
- v-sheet：　高さ、影、枠線付きのスペースが欲しい時
- v-card：　テキストやイメージを綺麗に（お仕着せだけど）配置したいとき

この中で、span だけは inline （他ば block）でサイズ指定が無視されるため、根本的に使い方が異なります。詳しくは下記リンク先の記事を見てください。

- [ボックスモデル](https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/The_box_model)

他については、以下の違いがあります。

```App.vue
<template>
  <v-container>
    <div class="text-h6 mt-2">共通</div>
    <span>幅(width)の指定は有効</span><br/>
    
    <div class="text-h6 mt-2">div</div>
    <div height="200px" 
      max-width="500px"
      class="bg-black rounded-lg"
      elevation="3">
      <span>height 指定は無視される</span><br/>
      <span>max-width 指定は無視される</span><br/>
      <span>デフォルトでpaddingが設定されていない</span><br/>
      <span>影(elevation)の指定ができない</span><br/>
      <span>背景色、文字色の指定は class で行う</span><br/>
      <span>角(rounded)の指定は有効</span><br/>
    </div>

    <div class="text-h6 mt-2">v-container</div>
    <v-container height="200px" 
      max-width="500px"
      class="bg-green-lighten-3 rounded-lg"
      elevation="3">
      <span>height 指定は無視される</span><br/>
      <span>max-width 指定は無視される</span><br/>
      <span>デフォルトでpaddingが設定されている</span><br/>
      <span>影(elevation) の指定ができない</span><br/>
      <span>背景色、文字色の指定は class で行う</span><br/>
      <span>角(rounded)の指定は有効</span><br/>
    </v-container>

    <div class="text-h6 mt-2">v-sheet</div>
    <v-sheet height="200px"
      
      max-width="500px"
      class="bg-red-lighten-3 rounded-lg"
      elevation="3">
      <span>height 指定は有効</span><br/>
      <span>max-width 指定は有効</span><br/>
      <span>デフォルトでpaddingが設定されていない</span><br/>
      <span>影(elevation) の指定ができる</span><br/>
      <span>背景色、文字色の指定は class で行う</span><br/>
      <span>角(rounded)の指定は有効</span><br/>
    </v-sheet>

    <div class="text-h6 mt-2">v-card</div>
    <v-card height="200px"
      max-width="500px"
      color="blue-lighten-3"
      tonal>
      <span>height 指定は有効</span><br/>
      <span>max-width 指定は有効</span><br/>
      <span>デフォルトでpaddingが設定されていない</span><br/>
      <span>色の指定は <b>color</b> で行う（背景色、文字色は自動で決まる）</span><br/>
      <span>影(elevation)の指定はできるが variant と競合することがある</span><br/>
      <span>角(rounded)は指定はできるが variant と競合することがある</span><br/>
    </v-card>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e017d1d5-ecfb-1ce5-4339-38b0fd05c5fe.png)

div はスタイルが何も指定されていないので、要素を単純にまとめたいだけの目的ならば div を使うのがよさそうです。要素をまとめたうえで、それらの要素にマージンやパディングをお手軽に設定したいときは v-container を、サイズ（高さ、最大幅など）を細かく指定したい場合は v-sheet を使います。

## v-card

v-card はお仕着せのスタイルが設定されている v-sheet と考えれば、だいたいあっていると思います。お任せスタイルで良い場合は v-card を使い、細かく指定したいなら v-sheet を使うのがよさそうです。

```App.vue
<template>
  <v-container>
    <div class="text-h6 mt-2">v-card</div>
    <v-card
      color="black"
      max-width="500px"
      variant="outlined"
    >
      <v-card-title>v-card の特徴 </v-card-title>

      <v-card-subtitle>お仕着せのスタイル付き v-sheet と考えればOK</v-card-subtitle>

      <v-divider></v-divider>

      <v-card-text>
        色や影、角などのスタイルは variant か props, color で指定することで、
        一括して自動で設定されます。class で設定することも可能ですが、
        指定内容によっては variant / props の設定が優先されることがあります。
      </v-card-text>

      <v-card-text>
        スタイルがお仕着せなので、v-card-text 内のテキストや
        v-card-action 内のボタンなどのスタイル（色、位置、寄せ）を
        class を使って変更しようとしても、反映されないことがあります。
      </v-card-text>

      <v-card-text>
        自力でスタイルを指定する場合は、v-sheet を使います。
        おまかせスタイルで良い場合は v-card を使うと便利です。
      </v-card-text>

      <v-card-actions>
        <v-btn>
          OK
        </v-btn>
        <v-btn>
          Cancel
        </v-btn>
      </v-card-actions>

      <v-divider thickness="5"></v-divider>

      <div class="text-body text-blue-darken-4 mx-6 mt-3">
        <p>
        div を使えば文字色やサイズ、マージンなども自由に変更できます。
        v-card-actions の外に v-btn を置けば、ボタンの色や寄せ方向も指定できます。
        </p>
        <p class="mt-3">
        ただ、それでも v-btn のスタイルは v-card のスタイル依存になるようです。
        全部自分で指定したいなら v-sheet を使うほうが良いでしょう。
        </p>
      </div>

      <div class="d-flex flex-row justify-end text-black">
      <v-btn >
        右寄せボタンの例
      </v-btn>
    </div>
    </v-card>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d6b1b95f-9cf0-c79b-b283-051e1247417b.png)

上の v-card では variant で outlined を指定しています。その指定に従って、テキストの色や背景色、影などの設定が自動的に決まっています。variant の優先度はかなり高いので、自力で class で色やサイズなどを変更しようとしても、完全には反映されないことがあります（もしくはスタイルと競合しておかしくなる）。

v-card の variant, prop については下記を見てください。

- [v-card](https://next.vuetifyjs.com/en/components/cards/)

## template について（余談）

template も div と同じように、複数の要素をまとめてグループ化する用途に使えます。ただし、template は v-for, v-if, v-slot などと同時に使わないと、内側に含んでいる要素を画面に表示してくれません。

例えば、次のようなことそすると、画面には hoge1, hoge2 のボタンは表示されません。

```App.vue
<template>
  <template>
    <v-btn>hoge1</v-btn>
    <v-btn>hoge2</v-btn>
  </template>

  <v-btn>Hoge3</v-btn>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/49c69009-d4a0-ba00-5a26-4ff6ea9c4be6.png)

Hoge3 だけ表示されます。そして、コンソールにエラーなどは表示されません。

しかし、v-if などと組み合わせると、表示されるようになります。

```App.vue
<template>
  <v-container>
    <template v-if="true">
      <v-btn>hoge1</v-btn>
      <v-btn>hoge2</v-btn>
    </template>

    <v-btn>Hoge3</v-btn>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d9eb84c8-48ba-585d-3640-3ec6aeebfd33.png)

これは v-if などの vue で処理する必要のある属性が指定されていると、vue がその処理をしたあとに、template タグそのものを消去してくれるからぽいです。消去されないで残っていると、template の内側にある要素は画面に表示されません。

- [HTML の template タグについて](https://developer.mozilla.org/ja/docs/Web/HTML/Element/template)

じゃあ template なんて使わず div を使ったらいいんじゃという気がしてきます。実際、div の場合は上記みたいな制約もないので、template を使う意味はないような気がします。

ですが、v-if と v-for を同時に使いたいときに、たまに （div じゃなくて） template じゃないとダメなケースがあります。

```App.vue
<template>
  <v-container>
    <ul class="mx-auto">
      <li v-for="k in 10" v-if="k != 5">
        item{{k}}
      </li>
    </ul>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f02517e7-fa7d-6f8a-b94a-adf9370aac85.png)

このように、5 のときだけ li 要素を作りたくない場合、v-for / v-if を組み合わせて、上のような感じに書きたくなります。しかし、この記述はうまく動きません。5 の場合でも li は表示されてしまいます。（しかもコンソールにワーニングが出る）

- [【Vue.js】`v-for`, `v-if` を一緒に使うのは避けよう](https://qiita.com/nakamo-03/items/632ce4b4ad9526fe18ef)

```App.vue
<template>
  <v-container>
    <ul class="mx-auto">
      <div v-for="k in 10">
        <li v-if="k != 5">
          item{{k}}
        </li>
      </div>
    </ul>
  </v-container>
</template>
```

じゃあこうしたらいいんじゃ？と思うんですけど・・・。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9287e880-29be-340f-4f93-8d7161cf00ac.png)

画面も期待通りの表示になるし、警告も出ないのでいいような気もします。

ですが、**ul 要素の子要素は li のみ** という HTML5 で決まっているルールがあります。上のように書かれたページは、最終的に ul の子要素が div になってしまっていて、このルールに違反しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/894c2725-8d96-e78d-f492-04c9d322cd28.png)

Chrome のデバッグツールで見ると、ul の子要素は div になっています。

ルール違反とはいえ、多くのブラウザではそれでも問題なく表示されはします。ただ、いつか期待通りの表示にならなくなったり、将来的にビルド時にエラーと言われて弾かれる可能性があります（かねえ？）。

こういうときは、template が使えます。

```App.vue
<template>
  <v-container>
    <ul class="mx-auto">
      <template v-for="k in 10">
        <li v-if="k != 5">
          item{{k}}
        </li>
      </template>
    </ul>
  </v-container>
</template>
```

このように、v-for のほうを template タグにすると、ビルドした後には template は綺麗に消えてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/22f4b625-92fb-3120-6cd9-6364e74a75ae.png)

デバッグツールで見ても、ちゃんと ul の子は li になっています。

このように、v-for / v-if を組み合わせて使いたいときに、template を使うと良い感じになることがあります。

vuetify3 のコンポーネントでも、v-row / v-col で上記のような v-for / v-if  を組み合わせるときに  div を使うと問題がおこります。

```App.vue
<template>
  <v-container>
    <v-row>
      <div v-for="k in 10">
        <v-col cols="3" v-if="k != 5">
          HOGE{{k}}
        </v-col>
      </div>
    </v-row>
  </v-container>
</template>
```

このように記述すると、結果は下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0d2df52e-db7f-63c7-cc1b-5514dcbbb1c7.png)


5番目の要素は弾かれてはいるのですが、`cols="3"` としているのに、v-col が横に9個全部が並んでしまっています。これは、v-row の直下の子として v-col が配置されていないせいです。

これは、こうなる理由を知らないと、死ぬほど悩むことになります（多分）。ここで、div を template にすると、期待通りの表示になります。

```App.vue
<template>
  <v-container>
    <v-row>
      <template v-for="k in 10">
        <v-col cols="3" v-if="k != 5">
          HOGE{{k}}
        </v-col>
      </template>
    </v-row>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6d550a23-4346-4a88-637d-5799e876fe45.png)

v-row / t-col 以外でも、内部的に d-flex や d-float を使ってる要素の直下に、ダミーの div をはさんでしまうと、レイアウトが崩れることがあります。

こういうことがあるので、 v-for / v-if 用のダミーの要素としては、div ではなく template を使うようにします。

ちなみに HTML 各要素の入れ子には制限があって、div を子要素にできない要素は結構あります。

- [【一覧表あり】HTML5でのタグの入れ子のルールを徹底まとめ](https://webliker.info/html/46840/)

div を直下に置けない、よく使うタグとしては ul, ol, select, table, p, span, h1-h6 などがあります。

こういった要素の直下の要素に対して v-for / v-if を組み合わせて使うときには、安易に div を使わず template を使うようにします。ちなみに div ではなく v-container とかを使っても、最終的には div に変換されてしまうので、やはりルール違反になります。

## v-layout について

Vuetify1.5 までは `v-layout` は Vuetify2 以降の `v-row` に相当する要素でした。検索すると、 `v-layout` を使って Grid System を利用する方法の説明が結構でてきますが、その説明は古いものです。

Vuetify3 での `v-layout` の位置づけはよくわかりません（ドキュメントでの説明はほぼ無いです）。ただ、配置される場所が固定されている一部の要素（`v-app-var`, `v-navigation-drawer>`, `v-footer`, `v-main` など）は、`v-layout` または `v-app` の内側にしか配置できません。`v-layout` が存在しないと、エラーになって正常にレンダリングされません。

ちゃんとコードをみたわけではないのですが、`v-layout` を置くことで、その場所に新しい座標系を作成していうような感じっぽいです。

# 要素配置の基本

## サイズの指定

だいたいの要素は `height`, `width` 属性でサイズを指定できます。要素に含まれるコンテンツの量やサイズが可変な場合は`max-height`, `max-width`, `min-height`、`min-width` を使うこともあります。

```App.vue
<template>
  <v-container>
    <div class="d-flex">
      <v-container class="bg-blue-lighten-4 mx-2">
        <v-btn width="200px" class="my-2">
          width=100px のボタン
        </v-btn>

        <v-btn width="20em" class="my-2">
          width=20em のボタン
        </v-btn>

        <v-btn width="20rem" class="my-2">
          width=20rem のボタン
        </v-btn>

        <v-btn height="10ex" class="my-2">
          height=10ex のボタン
        </v-btn>

        <v-btn height="40px" class="my-2">
          height=40px のボタン
        </v-btn>

        <v-btn width="25em" height="10em" class="my-2">
          width=30em, height=10em のボタン
        </v-btn>

        <v-divider thickness="5"></v-divider>
        <p>
          v-divider の縦幅は thickness で指定する。
        </p>

        <v-divider thickness="5" width="50%"></v-divider>
        <p>
          v-divider の横幅は width で指定する。
        </p>

        <div class="d-flex bg-white mt-3">
          <v-img
            class="mx-auto my-3"
            src="https://iconape.com/wp-content/files/no/113101/png/vuetify.png"
            height="100">
          </v-img>

          <v-img
            class="mx-auto my-3"
            src="https://iconape.com/wp-content/files/no/113101/png/vuetify.png"
            height="100"
            cover>
          </v-img>
        </div>

        <p>
          v-img は cover を指定するか否かによって、サイズの指定が同じでも表示の
          され方（リサイズされるか、クロップされるか）が変わります。
        </p>

      </v-container>
      <v-container class="bg-red-lighten-4 mx-2">

        <v-btn min-width="400px" class="my-2">
          min-width=400px のボタン
        </v-btn>

        <p>
        min-width を指定すると、ブラウザの横幅が小さい方向へリサイズされた
        ときでも、その幅以下にはならない。親要素や画面からはみでるようになる。
        </p>

        <v-sheet width="300px" class="bg-red-lighten-5 my-4">
          <v-text-field label="text field" hide-details="auto"></v-text-field>
        </v-sheet>

        <p>
        v-text-field のように width が指定できない要素は、v-sheet などの
        中に置いて、親要素側で width を指定する。
        </p>

        <v-list
            class="overflow-y-auto my-3"
            max-height="20ex"
            min-height="10ex">
            <v-list-item
                v-for="k in 2"
                :key="k">
                item {{k}}
            </v-list-item>
        </v-list>

        <v-list
            class="overflow-y-auto my-3"
            max-height="20ex"
            min-height="10ex">
            <v-list-item
                v-for="k in 5"
                :key="k">
                item {{k}}
            </v-list-item>
        </v-list>

        <p>v-list のように、中に含む要素が可変の場合は max-height、min-height 
          を指定することで、要素数が少ないときは高さを小さくしつつ、
          要素数が増えたときでも高さに上限を付けることができる。
        </p>

      </v-container>
    </div>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/49d39a1d-60f7-605d-8bb1-9abc3e83eb06.png)

サイズを指定するときの単位については、下記ページの単位、長さの項目を見てください。

- [CSS の値と単位](https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/Values_and_units#percentages)

要素によって指定が有効であるものと、そうでないものがあります。サイズ指定については、要素ごとにかなり制約が異なっているので、それぞれの要素のAPIのリファレンスを見てください。

## 通常の配置

block タイプの要素は、記述した純に画面の上から順番に配置されます。block タイプのすべての要素は、基本的に横方向に並んだ状態では表示されません。（改行が入ったような状態になる）

要素間のスペース（隙間）も、明示的に指定しない限りはゼロになります（基本）。

ちなみに `v-btn` はベータのときは block 要素だったのに、いつのまにか inline 要素になったようです。

```App.vue
<template>
<div>
  <p> HOGE1 </p>
  <p> HOGE2 </p>
  <p> HOGE3 </p>
  <p> HOGE4 </p>  
</div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3895ce59-e64b-2e95-7212-02f510fddc11.png)

## block 要素を横方向に並べる

`d-inline` を使うと、要素の配置後に改行がなされなくなり、結果的に横方向に配置できます。

```App.vue

<template>
<div>
  <p class="d-inline"> HOGE1 </p>
  <p class="d-inline"> HOGE2 </p>
  <p class="d-inline"> HOGE3 </p>
  <p class="d-inline"> HOGE4 </p> 
</div>
</template>
```

結果；

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c144985f-85ad-0683-1356-be3f9ae84765.png)

この方法は簡単ですが、寄せ方向の指定や均等割り付けはできません。また、`v-checkbox` のように `d-inline` を指定しても、横にならんでくれない要素もあります。

### d-flex による中央揃え、右寄せ

`<v-container>` もしくは `<div>` で囲んでから、`class="d-flex flex-row"` を指定すると、囲まれた要素が左寄せで横に並べられます。

```App.vue
<template>
  <div class="d-flex flex-row">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p> HOGE3 </p>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/82d0f2de-a205-da46-e74b-c4bbb2fa25ca.png)


`justify-center` で中央揃え、`justify-end` で右揃えになります。

```App.vue
<template>
  <div class="d-flex flex-row justify-center">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p> HOGE3 </p>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/afa9acaa-c597-a2b1-e20e-e62799418f64.png)

### 下寄せ、上寄せ、中央揃え

文字のサイズが違う要素を横に並べると、基本は上側がそろいます。

```app.vue
<template>
  <div class="d-flex flex-row justify-center">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p class="text-h3"> HOGE3 </p>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5afc84ee-d64b-5fea-f5df-bf246f9e480d.png)


上の結果では、文字がボタンの上側と揃っていて、見栄えが悪いです。下側に揃えるには、`align-end` を指定します。

```App.vue
<template>
  <div class="d-flex flex-row justify-center align-end">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p class="text-h3"> HOGE3 </p>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/09b56525-06f3-dadb-5b9d-e1683e26e15e.png)


上に揃えるのは align-start, 中央揃えは align-center です。

### 均等割り付け

均等揃え `justify-space-between` も指定するとこんな感じになります。

```App.vue
<template>
  <div class="d-flex flex-row justify-space-between">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p> HOGE3 </p>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/049db56f-4969-8e1b-dbd0-93d9d11a2454.png)

### 横方向の空白 (v-spacer)

v-spacer を置くと、その位置に目いっぱいの横方向の空白を挿入します。均等割り付けを指定した場合でも、下記のように v-spacer を置くと、その位置に目いっぱいの空白が置かれ、それ以外の要素がぎゅうぎゅう詰めにされます。

```App.vue
<template>
  <div class="d-flex flex-row justify-space-between">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <p> HOGE3 </p>
    <v-spacer></v-spacer>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6ce938c2-bc11-5a05-bb8c-f918954ba315.png)

v-spacer をうまく使うと、寄せ方向を指定しなくても、寄せたような感じに見せることができます。

```App.vue
<template>
  <div class="d-flex flex-row justify-space-between">
    <p> HOGE1 </p>
    <p> HOGE2 </p>
    <v-spacer></v-spacer>
    <p> HOGE3 </p>
    <v-spacer></v-spacer>
    <p> HOGE4 </p>  
  </div>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/043cfd8f-59d3-56bb-d429-a7671edd8376.png)

後述する `mx-auto` がきかない `v-checkbox`, `v-tabs`, `v-radio` などのコンポーネントを強引に中央寄せとか右寄せしたいときにも使えます。

v-app-bar, v-footer の中に並べたボタンやアイコンの間にスペースを入れたい場合や、v-list-item の中に横方向にいくつか要素を並べて、その間にスペースを空けたい場合にも使えます。

うまく使えば、d-flex や Grid を使わなくても、要素の位置を揃えたり、位置を調整したりすることもできます。

### v-layout と mx-auto  による中央寄せ

`<v-app>` か `<v-layout>` の直下に限り、`class="mx-auto"` で中央に寄せることができます。ベータ版のときは `v-container` などの下にあっても寄せられたのですが、どういうわけか 3.0.0 からはこうなったようです。


```App.vue
<template>
  <v-container>
    <v-layout>
      <v-btn class="mx-auto">Hoge1</v-btn>
    </v-layout>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/32157826-fbb7-3d3a-5356-0f41766a2015.png)

要素をひとつだけ中央に寄せたいときに便利です。

```App.vue
<template>
  <v-container>
    <v-layout>
      <v-btn class="mx-auto">Hoge1</v-btn>
      <v-btn class="mx-auto">Hoge2</v-btn>
    </v-layout>
    <v-layout>
      <v-btn class="mx-auto">Hoge3</v-btn>
    </v-layout>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8cf6ca77-7898-ac3d-f97b-3574f815ea49.png)


`v-layout` の中に複数要素を置くと、`d-flex` を指定した上で均等割り付けを指定したような状態で配置されます。`v-spacer` を使った間隔の調整も可能です。これはこれで、結構便利です。

ただし、この仕様は vuetify2 とは変わっているので、今後変更されるかもしれません。

## 要素の幅を指定して横方向に並べる

d-flex で横方向に並べることはできますが、要素ごとにサイズ（幅）を変えようとすると面倒です。

そんな時は `<v-row>` と `<v-col>` を使うことで、テーブルを作る要領で要素の配置ができます。

```App.vue
<template>
<v-container>
  <v-row>
    <v-col>  <v-btn>Hoge1</v-btn>  </v-col>
    <v-col>  <v-btn>Hoge2</v-btn>  </v-col>
    <v-col>  <v-btn>Hoge3</v-btn>  </v-col>
    <v-col>  <v-btn>Hoge4</v-btn>  </v-col>
  </v-row>
</v-container>
</template>
```

基本形は上記です。row が行に相当し、col が列に相当します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/af3fe833-fdba-02aa-cc1d-3faf3a2e05e2.png)


デフォルトでは均等割り付けになります。

v-col で cols を指定すると、それぞれの要素の幅（の割合）を指定できます。１行あたりの横幅を12として、それぞれの col の横幅を 1-12 の整数で指定します。

```App.vue
<template>
<v-container>
  <v-row>
    <v-col cols="2">  <v-btn>Hoge1</v-btn>  </v-col>
    <v-col cols="2">  <v-btn>Hoge2</v-btn>  </v-col>
    <v-col cols="4">  <v-btn>Hoge3</v-btn>  </v-col>
    <v-col cols="4">  <v-btn>Hoge4</v-btn>  </v-col>
  </v-row>
</v-container>
<v-container>
  <v-row>
    <v-col cols="2">  <v-btn block>Hoge1</v-btn>  </v-col>
    <v-col cols="2">  <v-btn block>Hoge2</v-btn>  </v-col>
    <v-col cols="4">  <v-btn block>Hoge3</v-btn>  </v-col>
    <v-col cols="4">  <v-btn block>Hoge4</v-btn>  </v-col>
  </v-row>
</v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a61c93fd-e4bd-a76a-6bb4-9998efd9d895.png)

`<v-btn>` で `block` を指定すると、与えられた幅いっぱいに広がります。下の行は Block を指定しているので、HOGE1 のボタンに比べると、HOGE3、HOGE4は2倍の横幅になっていることが分かります。

### セル内の要素の上下寄せ

セル内の要素を下に寄せるには、`<v-col>` のクラスで `d-flex align-end` を指定します。縦方向の中魚揃えは `align-center` です。

```App.vue
<template>
  <v-container>
    <v-row>
      <v-col cols="2">  <v-btn block>Hoge1</v-btn>  </v-col>
      <v-col cols="2">  <v-btn block>Hoge2</v-btn>  </v-col>
      <v-col cols="4" class="d-flex align-end">
        <p>FOO BAR</p>
      </v-col>
      <v-col cols="4">  <v-btn block>Hoge4</v-btn>  </v-col>
    </v-row>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0652f8ed-1ce7-d8b8-8f45-292fccab7ec7.png)


### セル内での中央寄せ

`block` を使わずに、要素を中央寄せするには `<v-col>` で `d-flex flex-row justify-center` を指定します。

~~`<v-col>` 内の要素がひとつだけなら、`mx-auto` で中央に寄せることもできます。~~ Vuetify 3.3.6 でも寄せられなくなっています。バージョンアップしても寄せられないままなので、どうやら仕様のようです。

```App.vue
<template>
  <v-container>
    <v-row>
      <v-col cols="2">  <v-btn>Hoge1</v-btn>  </v-col>
      <v-col cols="2">  <v-btn>Hoge2</v-btn>  </v-col>
      <v-col cols="4">
        <v-btn>Hoge3</v-btn>
      </v-col>
      <v-col cols="4">  <v-btn>Hoge4</v-btn>  </v-col>
    </v-row>

    <v-row>
      <v-col cols="2">  <v-btn>Hoge1</v-btn>  </v-col>
      <v-col cols="2">  <v-btn>Hoge2</v-btn>  </v-col>
      <v-col cols="4" class="d-flex flex-row justify-center">
        <v-btn>Hoge3</v-btn>
      </v-col>
      <v-col cols="4">  <v-btn>Hoge4</v-btn>  </v-col>
    </v-row>

    <v-row>
      <v-col cols="2">  <v-btn>Hoge1</v-btn>  </v-col>
      <v-col cols="2">  <v-btn>Hoge2</v-btn>  </v-col>
      <v-col cols="4">
        <v-btn class="mx-auto">Hoge3</v-btn>
      </v-col>
      <v-col cols="4">  <v-btn>Hoge4</v-btn>  </v-col>
    </v-row>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b34d0126-41f2-7027-5e85-715d36669da8.png)


### 行送り

ひとつの行の `cols` の合計値が12を超えていると、自動的に次の行に改行します。

```App.vue
<template>
  <v-container>
    <v-row>
      <v-col cols="3" v-for="k in 10" :key="k">
        <v-btn block>
          HOGE{{k}}
        </v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>
``` 

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/37a17268-dffc-63d2-72c5-13f46a6c7372.png)


### セルの縦方向の結合

セルを縦方向に結合することは、基本的にはできないぽいです。`no-gutters` を使うとセルの境目をなくすことができるので、連続しているセルが結合しているように見せることは可能です。

```App.vue
<template>
  <v-container >
    <v-row no-gutters >
      <v-col cols="12">
        <v-sheet class="bg-black pa-2">
          HOGE1
        </v-sheet>
      </v-col>
      <v-col cols="6">
        <v-sheet class="bg-black pa-2">
          HOGE2
        </v-sheet>
      </v-col>
    </v-row>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/444ea566-2251-04ea-32fe-88878814e09d.png)


しかし、あくまで結合したように見せるだけなので `<v-btn>` のような境界のある要素の結合には使えません。

次の例のように、複数の `<v-row>` を横に並べることで、疑似的に結合したように見せることも可能です。ただ、ブラウザによって表示が崩れることがあるようなので、多分よくないです。

```App.vue
<template>
  <v-container class="d-flex flex-row">
    <div>
      <v-row>
        <v-col>
          <v-btn>HOGE1</v-btn>
        </v-col>
      </v-row>
      <v-row>
        <v-col>
          <v-btn>HOGE2</v-btn>
        </v-col>
      </v-row>
      <v-row>
        <v-col>
          <v-btn>HOGE3</v-btn>
        </v-col>
      </v-row>
    </div>
    <div class="d-flex flex-column pl-2">
      <v-row>
        <v-col>
          <v-btn height="6.8em">HOGE1</v-btn>
        </v-col>
      </v-row>
      <v-row class="pt-0">
        <v-col>
          <v-btn>HOGE2</v-btn>
        </v-col>
      </v-row>
    </div>
  </v-container>
</template>

```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/74fc6bd2-0045-7db9-ab98-abc72fb0e357.png)

他にいい方法があったら教えてください。

Grid System を使うと、かなり自由にレイアウトすることが可能です。Grid System について下記を参照してください。

- [Grid System](https://next.vuetifyjs.com/en/components/grids/)

# 要素の位置の微調整 (Spacing)

- [Spacing](https://vuetifyjs.com/ja/styles/spacing/)

上のリンク先は Vuetify2 のものですが、Vuetify3 でも動きます

要素の位置を微妙に調整したいときは、スペーシングヘルパーと呼ばれる CSS ヘルパークラスを使います。

```App.vue
<template>
  <v-container>
    <v-container class="d-flex flex-row justify-space-between">
      <v-card width="45%" height="100px" class="bg-black">
        <v-btn color="primary">
          none
        </v-btn>
      </v-card>

      <v-card width="45%" height="100px" class="bg-black">
          <v-btn color="primary" class="mt-5">
            mt-5 (margin 5 to top)
          </v-btn>
      </v-card>

    </v-container>

    <v-container class="d-flex flex-row justify-space-between">
      
      <v-card width="45%" height="100px" class="bg-black">
        <v-btn color="primary" class="pt-5">
          pt-5 (padding 5 to top)
        </v-btn>
      </v-card>

      <v-card width="45%" height="100px" class="bg-black">
          <v-btn color="primary" class="pt-5 pl-5">
            pt-5 pl-5
          </v-btn>
      </v-card>

    </v-container>

        <v-container class="d-flex flex-row justify-space-between">
      
      <v-card width="45%" height="100px" class="bg-black">
        <v-btn color="primary" class="ml-5 mt-5">
          ml-5 mt-5
        </v-btn>
      </v-card>

      <v-card width="45%" height="100px" class="bg-black">
          <v-btn color="primary" class="pt-5 pl-5 mt-5 ml-5">
            pt-5 pl-5 mt-5 ml-5
          </v-btn>
      </v-card>

    </v-container>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d49382cf-eccc-05dc-6827-495db9181be2.png)

# 文字サイズ

- [Text and typography](https://vuetifyjs.com/ja/styles/text-and-typography/)

上記に一覧があります。基本、クラスで指定します。

```App.vue
<template>
  <v-container>

    <div class="text-h1">
      H1 SIZE
    </div>

    <div class="text-h3">
      H3 SIZE
    </div>

    <div class="text-h6">
      H6 SIZE
    </div>

    <div class="text-body-1">
      Body-1 size
    </div>

    <div class="text-caption">
      Caption size
    </div>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/78a3c720-e56a-a6f9-a1c4-712489d04664.png)

イタリックとかボールドとかの指定方法は、リンク先に書かれています。

- [Text and typography](https://vuetifyjs.com/ja/styles/text-and-typography/)

# フォント

## google fonts を使う場合

デフォルト（Robotoフォント）以外のフォントを追加するときは、webfontloader に読み込みの設定を追加します。以下は google font を使用する場合です。

```plugins/webfontloader.js
import webFontLoader from 'webfontloader';

export default defineNuxtPlugin( nuxtApp => {
  webFontLoader.load({
    google: {
      families: [
        'Roboto:100,300,400,500,700,900',
        'Lato:100,300,400,700,900',
        'Rubik+Microbe:400',
        'Patrick+Hand:400',
        'Noto+Sans+JP:400,700'
      ],
    },
  })
});
```

nuxt3 で使う場合は、ファイル名は `plugins/webfontloader.client.js` にします。

```app.vue
<template>
  <v-container>
    <p class="default-font">Roboto</p>
    <p class="default-font">日本語はこんな感じ</p>
    <p class="extra-font">Rubik Microbe</p>
    <p class="extra-font2">Patrick Hand</p>
    <p class="extra-font3">Lato</p>
    <p class="extra-font4">日本語はこんな感じ</p>
  </v-container>
</template>
<style>
.default-font {
  font-size: xx-large;
}
.extra-font {
  font-family: 'Rubik Microbe';
  font-size: xx-large;
}
.extra-font2 {
  font-family: 'Patrick Hand';
  font-size: xx-large;
}
.extra-font3 {
  font-family: 'Lato', sans-serif !important; 
  font-size: xx-large;
}
.extra-font4 {
  font-family: 'Noto Sans JP', sans-serif !important; 
  font-size: xx-large;
}
</style>
```

`<style>` タグ内でフォントを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b56c8cdc-ac40-3b28-7320-90159fe59c52.png)


なお `text-h1` などを併用すると、フォントが上書きされます。

```app.vue
<template>
  <v-container>
    <p class="text-h1">Text H1</p>
    <p class="text-6rem">Text 6rem</p>
  </v-container>
</template>
<style>
.text-h1 {
  font-family: 'Rubik Microbe';
}
.text-6rem {
  font-size: 6rem;
  font-family: 'Rubik Microbe';
}
</style>
```

結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8553e2d7-2fc2-6617-5484-76c05c11459a.png)

どうしても `text-h1` の `font-family` を上書きしたければ `!important` で上書きは可能です。

## ダウンロードした font を使う場合

ここでは `Pacifico-Regular.ttf` をダウンロードしたファイルとして例を挙げます。

### vite + vuetify3 の場合

ダウンロードした `/src/assets/fonts` 以下にフォントのファイルを置きます。次に `/src/assets/font.css` というファイルを作ります。

```src/assets/font.css
@font-face {
  font-family: 'Pacifico';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('@/assets/fonts/Pacifico-Regular.ttf') format('truetype');
}
```

`/src/main.js` で import します。

```src/main.js
import './assets/font.css'
```

フォントを使いたい `vue` ファイルの中の `style` でフォントを指定します。

```app.vue
<template>
  <v-container>
    <p class="text-h1">Roboto</p>
    <p class="custom-font">Pacifico</p>
  </v-container>
</template>
<style>
.custom-font {
  font-family: 'Pacifico';
  font-size: 6rem;
}
</style>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7cbdb1d6-57e7-fa30-cd4b-f2f86be73db9.png)

`yarn dev` は起動し直す必要があります。

### nuxt3 + vuetify3 の場合

ダウンロードしたファイルを `assets/fonts/Pacifico-Regular.ttf` に置きます。

`assets/font.css` というファイルを作ります。

```/assets/fonts/font.css
@font-face {
  font-family: 'Pacifico';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('~/assets/fonts/Pacifico-Regular.ttf') format('truetype');
}
```

`url` の指定方法が、公式のドキュメントだと `~assets/fonts/` となっているかもしれませんが、それだとエラーになります。

`nuxt.config.ts` に追記します。

```nuxt.config.ts
export default defineNuxtConfig({
    css: [
        ...
        '~/assets/fonts/font.css'
    ],
    ...
}
```

フォントを使いたい `vue` ファイルの中の `style` でフォントを指定します。

```app.vue
<template>
  <v-container>
    <p class="text-h1">Roboto</p>
    <p class="custom-font">Pacifico</p>
  </v-container>
</template>
<style>
.custom-font {
  font-family: 'Pacifico';
  font-size: 6rem;
}
</style>
```

結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/58df603c-ec70-206f-c192-503198664f5d.png)

`yarn dev` は起動し直す必要があります。

# カラー

## テーマを使う方法

カラーは、テーマの機能を使って、アプリ全体で統一された色 (primary, secondary など）を使うことが多いです。

- [Vuetify3: Theme configuration](https://next.vuetifyjs.com/en/features/theme/)

```App.vue
<template>
  <v-container>
    <v-btn color="primary">Primary</v-btn>
    <v-btn variant="outlined" color="error">Error</v-btn>
  </v-container>
</template>
```

結果（テーマ light の場合）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ace3d73e-4942-d2e0-f695-38130c67f1f5.png)

結果（テーマ dark の場合）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/755b24e3-2bec-cb2a-1ddc-5558e14386cf.png)

テーマの指定方法

```vuetify.js
    const vuetify = createVuetify({
        ...
        theme: {
            defaultTheme: 'dark' // 'light'
        }
        ...
    }
```

テーマの色をカスタマイズしたい場合は、下記のようにします。

```vuetify.js
    const vuetify = createVuetify({
        ...
        theme: {
            themes: {
                light: { // テーマ名
                    colors: { // 以下で色を指定する（下記はデフォルト色）{
                          primary: '#1976D2',
                          secondary: '#424242',
                          accent: '#82B1FF',
                          error: '#FF5252',
                          info: '#2196F3',
                          success: '#4CAF50',
                          warning: '#FFC107',
                    },
                },
            },
        }
    }
```

オリジナルのテーマを作って、それをデフォルトにしたい場合は、下記のようにします。下記では `bbled` という名前のテーマを作って、それをデフォルトにしています。

色の名前は下記の例に沿う必要は特にありません。英数字以外の文字を色名に使いたいときは、下記の `primary-darken-1` のようにクオーテーションで囲います。

```vuetify.js
    const vuetify = createVuetify({
        ...
        theme: {
            defaultTheme: 'bbled',
            themes: {
                bbled: {
                    dark: false,
                    colors: {
                        background: '#FFFFFF',
                        surface: '#FFFFFF',
                        primary: '#6200EE',
                        'primary-darken-1': '#3700B3',
                        secondary: '#03DAC6',
                        'secondary-darken-1': '#018786',
                        error: '#B00020',
                        info: '#2196F3',
                        success: '#4CAF50',
                        warning: '#FB8C00',
                    }
                },
            }
        }
    }
```

```App.vue
<template>
  <v-container>
    <v-btn color="primary">Primary</v-btn>
    <v-btn variant="outlined" color="error">Error</v-btn>
    <v-btn color="secondary-darken-1">Secondary-Darken-1</v-btn>
  </v-container>
</template>
```

：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/75d8c923-3975-4f0a-15e0-bee7d65db5d6.png)

## テーマを使わない方法

テーマを使わず、個別に色を指定したいときは下記の方法を使います。

背景色は `bg-`、テキストの色は `text-` を先頭につけて、`class` として指定します。ただし、`<v-btn>` のように背景とテキストの色がセットになっているモジュールは `color` で直接指定します。

色の名前は下記に一覧があります。

- [Colors](https://vuetifyjs.com/ja/styles/colors/#section-30de30c630ea30a230eb30ab30e930fc)

```App.vue
<template>
  <v-container>
    <v-container class="bg-black text-indigo-lighten-5 my-3">
      hogehoge
    </v-container>

    <v-card class="bg-purple darken-1 my-3">
      HOGE
    </v-card>
    
    <v-btn color="red-darken-3 my-3">
      HOGE1
    </v-btn>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/39550c34-1b8a-11e0-6d85-ea27cc37d239.png)

`<v-btn>` でクラスを使って色を指定しようとしても、うまく反映されません。


# アイコン (Meterial Design Icons)

`yarn create vuetify` でプロジェクトを作成したときは、何もしなくても使うことができます。 nuxt3 で使うときは `yarn add @mdi/font` と nuxt.confit.ts への css の追加が必要です。

```nuxt.config.ts
export default defineNuxtConfig({
    css: [
        "vuetify/lib/styles/main.sass",
        "@mdi/font/css/materialdesignicons.css"
    ],
    ...
}
```



下記サイトにあるアイコンが使えます。

- [Material Design Icons](https://materialdesignicons.com/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c90ad0fe-0143-f4af-9c53-0a32da5efab0.png)


たとえば、上の Account Circle のアイコンが使いたければ下記のようにします。

```App.vue
<template>
<v-app>
  <v-container>
    <v-icon>
      mdi-account-circle
    </v-icon>

    <v-icon>
      mdi-home
    </v-icon>

    <v-btn icon="mdi-magnify" color="primary">
    </v-btn>
  </v-container>
</template>
```

結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b71442d3-e571-9f38-40f2-6bb348005a98.png)


基本、`mdi-` の後ろにフォント名（ポップアップで表示される文字）を付けるだけです。`<v-btn>` で使う場合は `icon="mdi-iconname"` のようにして指定します。


# 結論

v-data-table は labs として実装されました。


- [Vuetify3 のレイアウトに関するメモ（この記事）](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)
- [Vuetify3 でよく使うコンポーネントのメモ（１）](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203)
- [Vuetify3 でよく使うコンポーネントのメモ（２）](https://qiita.com/mml/items/16030c4404b4a814956b)