LoginSignup
29
21

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-10-04

背景

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

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

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

たとえば、

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

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

@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の変数機能は無かったことになり、エラーになります。




CSS変数使えば良いんじゃない? :thinking:

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

CSS カスタムプロパティ (変数) の使用 - CSS: カスケーディングスタイルシート | MDN

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

理由1: 長い :thumbsdown:

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

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

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

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




SCSS変数で管理するやりかた

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

STEP1 CSS変数を用意し、ライトモード時・ダークモード時の色をそれぞれ指定する

: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変数を指定する。

$COLOR_THEME: var(--color-theme);
$COLOR_BASE: var(--color-base);
$COLOR_MAIN: var(--color-main);

STEP3 SCSS変数を好きな場所で使える :tada:

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

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




rgba() にも対応するなら

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

STEP1 用意した色のRGB値をそれぞれ別で指定する

: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変数を別で用意する。

$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変数を保管タグつきで使う。

p{
  color: rgba(#{$COLOR_RGB_THEME},.5);
}




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

29
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
21