Produced by Fourier

SASS(SCSS)とCSS変数を連携してダークモードを実装

Hirayama Hirayama カレンダーアイコン 2022.10.27

はじめに

Webサイトを作る上で CSS は避けては通れませんが、 CSS をわかりやすく書くことは難しく、作っていくうちに複雑になりすぎることがよくあります。

また、JavaScriptを使用して動的にページの見た目を変えることもよくあり、JavaScriptとも連携しやすいように書く必要があります。

この2つの問題はそれぞれ SASS(SCSS) CSSカスタムプロパティ で解決できるので、本記事では具体例として ダークモードの実装方法 について解説したいと思います。

なお、本記事では SASSSCSS の文法で記述します。

簡単な例

まずは SASS の変数機能と CSSカスタムプロパティ を使ってダークモードを実装します。

// 色をSCSS変数として定義する
$border-color-light: #000000;
$border-color-dark: #ffffff;
$text-color-light: #000000;
$text-color-dark: #ffffff;
$background-color-light: #ffffff;
$background-color-dark: #000000;

// テーマごとに変数を設定
.light-theme {
  --border-color: $border-color-light;
  --text-color: $text-color-light;
  --background-color: $background-color-light;
}

.dark-theme {
  --border-color: $border-color-dark;
  --text-color: $text-color-dark;
  --background-color: $background-color-dark;
}

body {
  background-color: var(--background-color);

  button {
    // CSSカスタムプロパティの値を使うように設定
    border-color: var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
  }
}

これはコンパイルすると、以下のような CSS になり、 light-themedark-theme クラスが定義され、それぞれ同じ CSSカスタムプロパティ が定義されています。

.light-theme {
    --border-color: #000000;
    --text-color: #000000;
    --background-color: #ffffff;
}

.dark-theme {
    --border-color: #ffffff;
    --text-color: #ffffff;
    --background-color: #000000;
}

body {
  background-color: var(--background-color);
}

body button {
    border-color: var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
}

生成された light-themedark-theme クラスをJavaScriptで切り替えることで、同じ名前の CSSカスタムプロパティ でもテーマごとに値が切り替わり、ダークモードの実装が実現できます。

値の生成

上記の例でも目的は達成できていますが、テーマごとに SASS 変数を定義し、 CSSカスタムプロパティ として定義する必要があるため、記述するのが大変です。 そのため、 SASS の機能を活用して、その手間を減らします。

$schemes: light, dark;

$scheme-colors: (
  border: (#000000, #ffffff), //1番目がライトテーマ、2番目がダークテーマ
  text: (#000000, #ffffff),
  background: (#ffffff, #000000)
);

@each $scheme in $schemes {
  // テーマごとのクラスを作成
  .#{$scheme}-theme {
    // 色を定義
    @each $name, $colors in $scheme-colors {
      $color: nth($colors, index($schemes, $scheme));
      --#{$name}-color: #{$color};
    }
  }
}

main {
  button {
    border-color: var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
  }
}

少しコードが複雑になりましたが、生成される CSS は同じです。このコードでは複数の SASS の機能を使用しています。

1つ目は $scheme-colors のマップ変数で、 bordertext の名前をキーとして、色を配列にして1番目にライトテーマ用、2番目にダークテーマ用の色をいれています。 こうすることで、テーマごとに同じ名前の変数を定義する必要がなくなり、コード量が減って楽になります。

2つ目は @each を使って $scheme$scheme-colors の変数を順番に取り出している点で、この部分で CSSカスタムプロパティ を同じように一気に定義しています。

このように書くことで、新しく色を追加したい場合でも最小限の手間で追加することが可能となりました。

RGB値の変数を定義

ここまででテーマごとの色の定義方法について解説しましたが、これらの値には透過値が入っておらず、後から透過値を組み合わせることができない問題があります。

そのため、透過値と組み合わせられるようにRGB値を定義します。

$schemes: light, dark;

$scheme-colors: (
  border: (#000000, #ffffff), //1番目がライトテーマ、2番目がダークテーマ
  text: (#000000, #ffffff),
  background: (#ffffff, #000000)
);

@each $scheme in $schemes {
  // テーマごとのクラスを作成
  .#{$scheme}-theme {
    // 色を定義
    @each $name, $colors in $scheme-colors {
      $color: nth($colors, index($schemes, $scheme));
      $r: red($color);
      $g: green($color);
      $b: blue($color);
      --#{$name}-color: #{$color};
      --#{$name}-r-color: #{$r};
      --#{$name}-g-color: #{$g};
      --#{$name}-b-color: #{$b};
      --#{$name}-rgb-color: #{$r, $g, $b};
    }
  }
}

main {
  button {
    border-color: var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
  }
}

これをコンパイルすると、以下のようになります。

.light-theme {
	--border-color: #000000;
	--border-r-color: 0;
	--border-g-color: 0;
	--border-b-color: 0;
	--border-rgb-color: 0, 0, 0;
	--text-color: #000000;
	--text-r-color: 0;
	--text-g-color: 0;
	--text-b-color: 0;
	--text-rgb-color: 0, 0, 0;
	--background-color: #ffffff;
	--background-r-color: 255;
	--background-g-color: 255;
	--background-b-color: 255;
	--background-rgb-color: 255, 255, 255;
}

.dark-theme {
	--border-color: #ffffff;
	--border-r-color: 255;
	--border-g-color: 255;
	--border-b-color: 255;
	--border-rgb-color: 255, 255, 255;
	--text-color: #ffffff;
	--text-r-color: 255;
	--text-g-color: 255;
	--text-b-color: 255;
	--text-rgb-color: 255, 255, 255;
	--background-color: #000000;
	--background-r-color: 0;
	--background-g-color: 0;
	--background-b-color: 0;
	--background-rgb-color: 0, 0, 0;
}

main button {
	border-color: var(--border-color);
	color: var(--text-color);
	background-color: var(--background-color);
}

CSSカスタムプロパティ が大量に定義されましたが、これで各色のRGB値が使用できるようになりました。

特徴的なのが —#{name}-rgb-color 変数で、値の中にカンマが入っています。このカンマ入りの CSSカスタムプロパティ は、以下のように CSSrgba と組み合わせて使用することで透過値を設定できます。

div {
  background: rgba(var(--background-rgb-color), .1);
}

まとめ

本記事では SASSCSSカスタムプロパティ を連携してダークテーマの実装をしました。  SASS を使うことで素の CSS よりも簡潔に書くことができ、 CSSカスタムプロパティ で動的な要素も比較的簡単に実装できました。

この記事で紹介した機能は様々な形で応用できるので、読者の皆様の参考になれば幸いです。

Hirayama

Hirayama slash forward icon Engineer

業務では主にPHPやTypeScriptを使用したバックエンドアプリケーションやデスクトップアプリケーションの開発をしています。趣味は登山。

関連記事