Angular＋sass（scss）によるカラーテーマ切り替えベストプラクティス

# Angular＋sass（scss）によるカラーテーマ切り替えベストプラクティス
![https___angular-changetheme.stackblitz.io-Google-Chrome-2018_12_09-19_27_33.gif](https://qiita-image-store.s3.amazonaws.com/0/195903/10d7bc8d-50dc-12ce-2507-6c52234f2e8e.gif)

この記事は，[Angular Advent Calendar 2018](https://qiita.com/advent-calendar/2018/angular)，10日目の記事です．

## TL;DR
- [オンラインデモ](https://angular-changetheme.stackblitz.io/)
- [コード全量](https://stackblitz.com/edit/angular-changetheme)

## 目指したかったもの
- WEBで，各要素の色を，瞬時に切り替えたい
- 全部css（sass，もといscss）で管理したい
- 色は，**scssの変数で1か所で管理したい**
- このご時世にaddClassとか，removeClassとかしたくない……．
- 各要素ごとに，テーマごとのcssを全部定義するのも，メンテできなくなるのでしたくない．
- 結論，テーマごとに定義した色変数を用いて，それをスマートに切り替えてくれるもの

## 執筆動機
- 上記要件を満たした実装が，検索してもでてこなかった
- よくあるのは，要素ごとに色を定義して，上位クラス（wrapperとか）のクラスをremoveClass，addClassで付け替えることによる切り替え例．
- もっとスマートにできるはず，かつ色も変数化できるはず，と頭を悩ませて，一応落としどころを見つけたので共有したい．

## 考えた構成
- １，Wrapperクラスを，テーマ分生成する．ただし，色の定義は1回のみとする．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195903/9edca3a9-3a0d-1d07-ccff-48a2951d3cb2.png)

- ２，Wrapperクラスを，Angularのバインドによって切り替える．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195903/833b4345-92de-abfb-a51c-0e0af26f4aa5.png)

## コード解説
- １，Wrapperクラスを，テーマ分生成する．ただし，色の定義は1回のみとする．

```scss
// 適当な値で変数を初期化しておく
$back: #000000;
$font: #000000;
$bttn: #000000;
$btnf: #000000;

// テーマの数だけループする
@for $i from 1 through 2 {

  .wrapper#{$i} {
    @if $i == 1 {
        // テーマごとに色を定義する，1回で良い．
        $back : #F4F3EE;
        $font : #463F3A;
        $bttn : #E0AFA0;
        $btnf : #FFFFFF;
    } @else {
        $back : #000000;
        $font : #FFFFFF;
        $bttn : #32FFFB;
        $btnf : #38005B;
    }

    // スタイリングは，テーマごとに切り替えなくてよい．
    background-color: $back;
    color: $font;
    width: 100%;
    height: 100%;
    padding: 0;
    margin: 0;

    .block{
      padding: 20px;
      h1 {
        font-size: 24px;
        padding: 0;
        margin: 0;
      }
      button {
        background-color: $bttn;
        color: $btnf;
      }
    }
  }
}

```

- ２，Wrapperクラスを，Angularのバインドによって切り替える．

.html

```html
<!-- クラス名をバインドしている -->
<div [(class)]="colorTheme">
  <div class="block">
    <h1>Change Color Theme with .scss and .ts</h1>
    <p>
      toggle and change theme :)
    </p>
  </div>
  <div class="block">
    <button mat-button>This is the Button</button>
  </div>
  <div class="block">
    <mat-slide-toggle (change)="changeColor($event)">
        On Dark
    </mat-slide-toggle>    
  </div>
</div>

```


.ts

```ts

import { Component } from '@angular/core';
import { MatSlideToggle } from '@angular/material';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.scss' ]
})
export class AppComponent  {
  name = 'Angular';

  // バインドするテーマ
  public colorTheme = 'wrapper1';

  constructor(){
    this.colorTheme = 'wrapper1';
  }

  // toggle event
  // トグルされるたびに，バインドするクラス名を変更する
  public changeColor(e){
    if(e.checked) {
      // to dark
      this.colorTheme = 'wrapper2';
    } else {
      // to light
      this.colorTheme = 'wrapper1';
    }
  }
}
```

## 終わりに
- この仕組みの優れたポイントは，色の定義を1極集中管理しながら，色の切り替えが行えるところである．
- とはいえラッパーの切り替えや，scssのループなどは決して可読性は高くないので，もう少し改良ができればしたい．

---
明日は@kimamulaさんの記事です．
よろしくお願いいたします．