Nuxt.jsに組み込んだBulmaでスティッキーフッター (sticky footer) を実現する

# はじめに

前回書いた記事「[:link: Nuxt\.jsにBulmaを組み込んだら、Vuexストアが理解できた件](https://qiita.com/isamusuzuki/items/5ec800e423a3a56ef03d)」の続きみたいなものです。少なくとも設定は同じです。

Bulmaには [:link: Footer](https://bulma.io/documentation/layout/footer/) が、ちゃんと1ページ使って説明されているのに、下部に固定化する方法についてはなにも言及していません。どうやって実現するのかなと調べたら、レイアウトファイルひとつで簡単に実現できたという、またまた**アハ体験**が待っておりました。

## 駆け足で、前回の記事を再現

- create-nuxt-appコマンドを使って`avocado`という名前のNuxt.jsアプリを作成
- `pages`ディレクトリに`about.vue`と`contact.vue`の2つのファイルを作成し、インデックスページ以外のページを用意
- `components`ディレクトリに`Navbar.vue`を作成し、ナビゲーションメニューのコンポーネントを用意
- `layouts/default.vue`ファイルを編集し、ナビゲーションメニューのコンポーネントをレイアウトファイルに取り付け
- `npm run dev`コマンドを叩いて開発サーバーを起動

`avocado`のディレクトリの中はこんな感じになっています

```text
|--components/
|    |--Logo.vue ... index.vueが使用するコンポーネント
|    `--Navbar.vue ... ナビゲーションメニュー
|--layouts/
|    `--default.vue ... デフォルトのレイアウトファイル
`--pages/
     |--about.vue ... 新たに作成したページ
     |--contact.vue ... 新たに作成したページ
     `--index.vue ... 最初から用意されているトップページ
```

前回の記事ではページ遷移後のメニューのトグルにVuexストアを使っていましたが、@takanoripさんの貴重なコメントにより、`Navbar.vue`ファイルだけで実現できるようになりました。`store/index.js`ファイルは登場しません。

## フッターコンポーネントの作成

`components`ディレクトリに`Bottom.vue`ファイルを作成します。

```html:components/Bottom.vue
<template>
  <footer class="footer">
    <div class="container">
      <div class="content has-text-centered">
        <p>
          &copy; 2018 Avocado
        </p>
      </div>
    </div>
  </footer>
</template>
```

今回は、新しいレイアウトファイルを用意します。
`layouts`ディレクトリに`stickyfooter.vue`ファイルを作成します。
そこにフッターコンポーネントを取り付けます

```html:layouts/stickyfooter.vue
<template>
  <div>
    <navbar/>
    <nuxt/>
    <bottom/>
  </div>
</template>

<script>
import Navbar from '~/components/Navbar.vue'
import Bottom from '~/components/Bottom.vue'

export default {
  components: {
    Navbar,
    Bottom
  }
}
</script>
```

なぜ`Footer.vue`ではなく、`Bottom.vue`というファイル名にしたかというと、コンポーネントを取り付けるときに、`<footer/>`という要素名が、すでにHTML5で採用された要素とダブるからです。

### 話の流れとは直接関係ない修正

`pages/index.vue`ファイルのスタイル定義が全ページに影響を及ぼしていて、こちらが意図したレイアウトの邪魔をするので、ローカルスコープにします。つまり「そのスタイル定義はそのページのみで有効」にさせます。

```html:pages/index.vue
<!-- <style>を<style scoped>に変更 -->
<style scoped>
.container
{
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
...
</style>
```

## すでにあるページに新しいレイアウトを適用

ページは何も指定しなければ、自動的にデフォルトのレイアウトが適用されますが、以下のように指定すればそのレイアウトファイルが適用されます。

```html:pages/contact.vue
<template>
  <div>
    <section class="hero is-info is-bold">
      <div class="hero-body">
        <h1 class="title is-size-2">
          Contact
        </h1>
        <h2 class="subtitle is-size-4">
          お問い合わせ
        </h2>
      </div>
    </section>
    <div class="container">
      お問い合わせ
    </div>
　　</div>
</template>

<script>
export default {
  layout: 'stickyfooter'
}
</script>
```

その結果がこちらになります。

![01a.png](https://qiita-image-store.s3.amazonaws.com/0/48056/ae3e05f4-be3a-edcc-a1b6-f40242dbcbb5.png)

はい、フッターが浮いております。フッターの下に何もない（恥ずかしい）空間がある。
Bulmaのフッターは特に極太仕様になっておりますが、それでも、スマホの縦長画面では浮いてしまいがちです。このフッターをどうやって下げるかが、本日のお題です。

やっと辿り着いた感が半端ないですが、間もなく終わります。

## スティッキーフッター (sticky footer)の実現

`layouts/stickyfooter.vue`ファイルを修正します。
`sf-site-all`と`sf-site-content`という２つのCSSクラスを追加します

```html:layouts/stickyfooter.vue
<template>
  <div class="sf-site-all">
    <navbar/>
    <nuxt class="sf-site-content"/>
    <bottom/>
  </div>
</template>

<script>
import Navbar from '~/components/Navbar.vue'
import Bottom from '~/components/Bottom.vue'

export default {
  components: {
    Navbar,
    Bottom
  }
}
</script>

<style>
.sf-site-all {
  min-height: 100vh; /* 全体の高さを最低でもビューポートの100%にする */
  display: flex; /* 子クラスを横並びにする */
  flex-direction: column; /* 子クラスの横並びの方向を縦にする */
}
.sf-site-content {
  flex: 1; /* flexに1つだけ数値を指定するとその要素は伸びる */
}
/* NavbarとBottomにはflexを指定しないので伸びない */
/* 結果としてページファイルの中味だけが伸びて、ビューポート100%を実現 */
/* Bottomは下に貼り付く。スティッキーフッターを実現 */
</style>
```

その結果がこちらです。

![2a.png](https://qiita-image-store.s3.amazonaws.com/0/48056/7f192672-b14c-3a2c-646d-1d6798153db3.png)

## 私のアハ体験ふたつ

「flexboxを使うとこんなに簡単にスティッキーフッターが実現できてしまうのか！」というのがひとつ。今まで後生大事にとっておいたスティッキーフッターのためのCSSテンプレートは捨ててしまいました。

「レイアウトファイルとページファイルを組み合せるための目印になっている`<nuxt/>`にもクラス名を付加してよかったんだ！」というのがもうひとつ。どこにも書いてなかったので、できるとは思わなかったのですが、あとから考えてみたら、「どうしてできないと思ったのか？」のほうが不思議ですね。

## 最後に

冒頭にも書いた通り、Bulmaのフッターを下部に固定する方法はどこにも載っていないのですが、Bulmaの作者からすると「なんで、そんなことわざわざ書かなきゃいけないの？」って感じなんだと思います。「Flexboxを採用したBulmaを採用したあなたなら知ってて当然でしょう」という感覚。いずれ私もそっち側の人間になりたいなと思いつつ、その過程で生まれた**アハ体験**を、次の人のために記事にしておく次第です。

面白いと思っていただけたら「いいね」をクリックしてください。励みになります。