背景
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変数使えば良いんじゃない?
CSS公式でもCSS変数というものが使えます。IE以外なら、生のCSSそのままで変数を定義して使い回すことができるので、これを使えばダークモード・ライトモードに応じて変数を上書きできます。
が、これは以下の理由からできるだけそのまま使いたくありません。
理由1: 長い
$COLOR_THEME: red; // SCSS変数定義
p{ color: $COLOR_THEME } // SCSS変数使用
:root{ --color-theme: red } // CSS変数定義
p{ color: var(--color-theme) } // CSS変数使用
理由2: rgba()
指定ができない
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変数を好きな場所で使える
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とか使うのもありかもしれません。もっとステキな方法あったらぜひおしえてください。