【BootstrapVue】 Stacked table のスタイルを Sass でカスタマイズする

# はじめに

[BootstrapVue の Stacked table ](https://bootstrap-vue.js.org/docs/components/table/#stacked-tables) というものがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/1a6c403c-9dbd-6ddf-31be-ad9c0f7915e4.png)


普通のテーブルだとヘッダーにあたる部分が左に表示され、データを key, value の形式で表すことができます。
`b-table` タグに `stacked` というオプションを入れるだけでこのようになってくれるので非常に頼もしいのですが、
key 項目の**文字左寄せ**や**背景色の変更**など、スタイルを自由にできないところが難点です。

そこで、Bootstrap の設定を上書きすることで、このようなカワイイ stacked table を作りたいと思います！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/f26126b1-b4b2-e121-6e08-16c299e80ddf.png)
*アドベントカレンダーなのでクリスマスカラー🎄*

- vue-cli でのアプリ開発をしたことがある方を対象に書いています。
- 内容は主に Sass ですが、解説というより「コピペしたら使えるもの」を目指しています。
- 完全なコードは[こちら(github)](https://github.com/bakupen/stacked-table-custom)

# 環境
vue-cli 3
bootstrap-vue 2.0.2


# 準備
### BootstrapVue をインストール

[公式ドキュメントの Getting Started ](https://bootstrap-vue.js.org/docs/)に沿って BootstrapVue の使える環境にします。

`$ npm install bootstrap-vue bootstrap`

```main.js
import Vue from 'vue'
import App from './App.vue'
import BootstrapVue from 'bootstrap-vue'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

### Stacked table を作成

```HelloWorld.vue
<template>
  <div class="content-area">
    <b-table
      stacked
      :items="items"
      :fields="fields"
    >
    </b-table>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      fields: [
        { key: 'id', label: '商品コード' },
        { key: 'name', label: '商品名' },
        { key: 'group', label: '分類' },
        { key: 'allergies', label: 'アレルギー' },
      ],
      items: [
        {
          id: '628402942632',
          name: 'えびおかき',
          group: '菓子',
          allergies: 'えび'
        }
      ]
    }
  }
}
</script>

<style scoped>
.content-area {
  width: 550px;
  margin: auto;
}
</style>
```

商品詳細画面を想定し、items はオブジェクトひとつです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/016fdff1-5450-70c7-9135-28205b881032.png)


今から

- key 項目の文字を左寄せにする
- key 項目の背景色を変える
- value 項目の背景を縞々にする
- ボーダーを消す

をやります。

# スタイル上書きファイルの作成

#### 1. Sass が使える環境にします
`$ npm install sass-loader node-sass`
※ Windowsの場合、Rubyのインストールが必要だそうです。詳しくはググってください。

#### 2. 適当な場所に .scss ファイルを作ります
今回は `src/assets` の下に scss ディレクトリを噛ませ、 custom.scss という名前で作りました。

```
src
├── App.vue
├── assets
│   ├── logo.png
│   └── scss
│       └── custom.scss
├── components
│   └── HelloWorld.vue
└── main.js
```

#### 3. main.js を書き換えます

```main.js
import Vue from 'vue'
import App from './App.vue'
import BootstrapVue from 'bootstrap-vue'

//import 'bootstrap/dist/css/bootstrap.css'      //　削除
//import 'bootstrap-vue/dist/bootstrap-vue.css'  // 削除
import './assets/scss/custom.scss'               // 追加
Vue.use(BootstrapVue)
// ・・・
```

#### 4. custom.scss で Bootstrap の設定を import します

```custom.scss
// Bootstrap and its default variables
@import "~bootstrap/scss/bootstrap";
@import "~bootstrap-vue/src";
```

これで準備完了です！

# Sass を書いていく

Sass には記法が2つ、sass 記法と scss 記法があります。
Bootstrap が scss 記法で書かれているので、そちらに合わせて scss で書きます。

### key 項目の文字を左寄せにする
先ほどの import の下から書いていきます。

```custom.scss
// ・・・
@if $bv-enable-table-stacked {
  .table.b-table {
    &.b-table-stacked {
      @each $breakpoint in map-keys($grid-breakpoints) {
        $next: breakpoint-next($breakpoint, $grid-breakpoints);
        $infix: breakpoint-infix($next, $grid-breakpoints);

        &#{$infix} {
          @include media-breakpoint-down($breakpoint) {

            > tbody {
              > tr {
                > [data-label] {
                  &::before {
                    text-align: left;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

key 項目の要素は `<th>` ではなく、`:before` で表現されています。
*だから容易にカスタマイズできないんだろうな…*

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/a3715703-582a-da39-86f6-21de3b7e86fc.png)


### key項目の背景色を変える

```custom.scss
$b-table-stacked-heading-width: 27%;

// Bootstrap and its default variables
@import "~bootstrap/scss/bootstrap";
@import "~bootstrap-vue/src";

// ・・・

            > tbody {
              > tr {
                > td {
                  padding: 0;
                  position: relative;
                }
                > [data-label] {
                  > div {
                    width: 100%;
                    padding: $table-cell-padding;
                    padding-left: 29%;
                  }
                  &::before {
                    text-align: left;
                    color: #ffffff;
                    background-color: #ca1818;
                    padding: $table-cell-padding;
                    position: absolute;
                    height: 100%;
                  }
                > [data-label]:nth-of-type(odd) {
                  &::before {
                    background-color: #157512;
                  }
                }
                }
              }
            }
// ・・・
```

#### ポイント解説

- 一番上の`$b-table-stacked-heading-width` は Bootstrap-vue の scss ファイル内で使われている変数です。
この変数を上書きすることで、key 項目の幅を調節できます。

- `... > [data-label] > div` の `padding-left: 29%;` は、`:before` 要素の幅分スペースを空けてあげるための記述です。

- `:before`要素の height を100%にすることで、value 項目の改行に耐えることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/719e6d5a-ab50-efc6-eb47-f0b0e00ea5b9.png)


### value項目の背景を縞々にする

```custom.scss
// ・・・
            > tbody {
              > tr {
                > td:nth-of-type(odd) {
                  background-color: $table-accent-bg;
                }
// ・・・
```

`$table-accent-bg` も Bootstrap に元からある変数です。
普通の table に striped オプションをつけた時と同じ色の縞々になります。

### ボーダーを消す

```custom.scss
.table {
  td {
    border-top: 0px;
  }
}
```

あとは微調整して…
### できました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/f26126b1-b4b2-e121-6e08-16c299e80ddf.png)

# おわりに

上書きする前のスタイルは `./node_modules/bootstrap-vue/src/components/table/_table.scss ` で確認できます。

Sass というものを初めて触りましたが、css をプログラムっぽく書けるのが面白かったです。
また、一度設定すると全ての vue コンポーネントに反映するので、プロジェクト全体に統一感を与えることができるのも良いなと思いました。
*primary とかの variant color をカスタマイズできるのがめっちゃ便利✨*

それでは、よいクリスマスを🎅🍻🎅

---
ハンズラボアドベントカレンダー2019 👉18日目は @mimimi-no-sesese さんです🏓