Webのダークモード対応をSCSS変数で管理する方法を考える

# 背景
`prefers-color-scheme` という Media Query を主要ブラウザがサポートしたため、Webでもダークモードに対応がしやすくなりましたね。CSSファイルに「**ユーザがダークモードにしていたらこのCSS、ライトモードにしていたらこのCSSを適応**」というように簡単に指定できるようになります。

```scss
@media (prefers-color-scheme: light) {
  // ライトモードのときのCSS
}
@media (prefers-color-scheme: dark) {
  // ダークモードのときのCSS
}
```

詳しくは [CSSだけでWebページをダークモード対応。ついにChromeにも対応した prefers-color-scheme が超便利｜平田 / U-NEXT｜note](https://note.mu/psephopaiktes/n/n878424784a1b) あたりの記事でも読んでやってください。で、このダークモードなのですが、理想をいうとちゃんと変数使って管理したいですよね。

たとえば、

```scss
$COLOR_THEME; // ブランドカラー、テーマカラー、アクセントカラーとして使う色
$COLOR_BASE; // 主に背景色として使う色
$COLOR_THEME; // 主に文字色や罫線に使う色
```

みたいな変数を用意しておいて、

```scss
@media (prefers-color-scheme: light) {
  $COLOR_THEME: red;
  $COLOR_BASE: white;
  $COLOR_MAIN: black;
}
@media (prefers-color-scheme: dark) {
  $COLOR_THEME: #cc0000;
  $COLOR_BASE: black;
  $COLOR_MAIN: white;
}

body{
  background: $COLOR_BASE;
  color: $COLOR_MAIN;
}
h1{
  color: $COLOR_THEME;
}
```

みたいに書いておいて、**ダークモードかライトモードかで変数の中身が変わる** とステキじゃないですか？ しかし、この指定はうまくいきません。御存知の通りSCSSは事前にCSSに変換して使う言語なので、これをCSSに変換するとSCSSの変数機能は無かったことになり、エラーになります。


<br><br><br>


# CSS変数使えば良いんじゃない？ :thinking: 
CSS公式でも**CSS変数**というものが使えます。IE以外なら、生のCSSそのままで変数を定義して使い回すことができるので、これを使えばダークモード・ライトモードに応じて変数を上書きできます。

> [CSS カスタムプロパティ (変数) の使用 - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties)

が、これは以下の理由からできるだけそのまま使いたくありません。

### 理由1: 長い :thumbsdown: 

```SCSS
$COLOR_THEME: red; // SCSS変数定義
p{ color: $COLOR_THEME } // SCSS変数使用

:root{ --color-theme: red } // CSS変数定義
p{ color: var(--color-theme) } // CSS変数使用

```

### 理由2: `rgba()` 指定ができない :thumbsdown::thumbsdown: 

```SCSS
p{ color: rgba($COLOR_THEME,.5) } // OK
p{ color: rgba(var(--color-theme),.5) } // エラー
```


<br><br><br>


# SCSS変数で管理するやりかた
上記を解決する、一番マシかと思われる設計を考えてみたのが以下です。IEには対応してませんのであしからず。

### STEP1 CSS変数を用意し、ライトモード時・ダークモード時の色をそれぞれ指定する
```scss
:root{
  @media (prefers-color-scheme: light) {
    --color-theme: red;
    --color-base: white;
    --color-main: black;
  }
  @media (prefers-color-scheme: dark) {
    --color-theme: #cc0000;
    --color-base: black;
    --color-main: white;
  }
}
```

### STEP1 同名のSCSS変数を用意して、先程のCSS変数を指定する。
```scss
$COLOR_THEME: var(--color-theme);
$COLOR_BASE: var(--color-base);
$COLOR_MAIN: var(--color-main);
```

### STEP3 SCSS変数を好きな場所で使える :tada: 
```scss
body{
  background: $COLOR_BASE;
  color: $COLOR_MAIN;
}
h1{
  color: $COLOR_THEME;
}
```

おめでとうございます。これで、無事にユーザーのカラーモードに応じてWebページのデザインが変更されます。しかし、このままだと `rgba($COLOR_THEME,.5)` は `rgba(var(--color-theme),.5)` に変換されるので、エラーになってしまいます。


<br><br><br>


# `rgba()` にも対応するなら
面倒ですが、指定したい色のRGBそれぞれを一度変数化せざるを得なそうです。以下のように指定するのが良いと思います。

### STEP1 用意した色のRGB値をそれぞれ別で指定する
```scss
:root{
  @media (prefers-color-scheme: light) {
    --color-theme: red;
    --color-theme-r: 255;
    --color-theme-g: 0;
    --color-theme-b: 0;

    --color-base: white;
    --color-base-r: 255;
    --color-base-g: 255;
    --color-base-b: 255;

    --color-main: black;
    --color-main-r: 0;
    --color-main-g: 0;
    --color-main-b: 0;

  }
  @media (prefers-color-scheme: dark) {
    --color-theme: #cc0000;
    --color-theme-r: 204;
    --color-theme-g: 0;
    --color-theme-b: 0;

    --color-base: black;
    --color-base-r: 0;
    --color-base-g: 0;
    --color-base-b: 0;

    --color-main: white;
    --color-main-r: 255;
    --color-main-g: 255;
    --color-main-b: 255;
  }
}
```

### STEP2 RGB展開用のSCSS変数を別で用意する。
```scss
$COLOR_THEME: var(--color-theme);
$COLOR_BASE: var(--color-base);
$COLOR_MAIN: var(--color-main);

$COLOR_RGB_THEME: var(--color-theme-r),var(--color-theme-g),var(--color-theme-b);
$COLOR_RGB_BASE: var(--color-base-r),var(--color-base-g),var(--color-base-b);
$COLOR_RGB_MAIN: var(--color-main-r),var(--color-main-g),var(--color-main-b);
```

### STEP3 `rgba()` を使うときはRGB展開用のSCSS変数を保管タグつきで使う。
```scss
p{
  color: rgba(#{$COLOR_RGB_THEME},.5);
}
```

<br><br><br>

以上です。ダークモード対応するなら、現状これがいちばんましな色の管理方法じゃないですかね。mixinとか使うのもありかもしれません。もっとステキな方法あったらぜひおしえてください。