数行の CSS だけでお手軽にダークモードをやる方法の比較
はじめに
数行の CSS だけで(不完全ではあるが)お手軽にダークモードを実現する方法はいくつかある。
自分が知っているのは mix-blend-mode: difference; を使う方法と filter: invert(1); を使う方法で、これらの違いを調査しどちらを使うべきなのか考えてみる。
mix-blend-mode を使う方法について
全体に background: #fff; なレイヤーを張り、mix-blend-mode: difference; で下の色との差分をとる方法。
画像などは isolation: isolate; で mix-blend-mode の対象から除外する。
code:style.css
.container {
height: 100vh;
--dark: 1; /* JS でこれを 0 に変更してモードを切り替える */
}
.container::before {
position: fixed;
width: 100vw;
height: 100vh;
pointer-events: none;
content: "";
mix-blend-mode: difference;
opacity: var(--dark);
transition: opacity 1s;
}
img {
isolation: isolate;
}
pros/cons
色を自在に調整できる
コード量がやや多い
Windows の Chrome 限定で文字が潰れて見える
background: #fff; だと分からないが #000 に近づけるほど目立つ
絵文字が反転され壊滅する
一部にだけ適用するのが難しい?
filter を使う方法について
そのまま filter: invert(1); で色を反転する方法。
画像などは再度 filter: invert(1); をかけて色を戻す。
(isolation: isolate; は mix-blend-mode にしか効果がない?)
code:style.css
.container {
height: 100vh;
--dark: 1; /* JS でこれを 0 に変更してモードを切り替える */
filter: invert(var(--dark));
transition: filter 1s;
}
.container img {
filter: invert(var(--dark));
transition: filter 1s;
}
pros/cons
コード量が少ない
色の調整が難しい
filter: invert(0.9); のようにした場合、穏やかにはなるが画像の色が変わってしまう
transition と併用すると画像が一瞬灰色になる
絵文字の色が反転され壊滅する
比較
filter のほうが手軽だが、色を調整したり transition をかけたりするなら mix-blend-mode しか選択肢がない。
絵文字に関してはどちらも対処が難しいため、絵文字を使う前提なら素直にダークモード用の CSS を用意すべきか。
絵文字に関して
filter: hue-rotate(180deg); を使うと、絵文字の色をある程度は戻せるが画像も反転されてしまう。
ここで画像にだけ filter: hue-rotate(180deg); を再度かけると、ある程度は戻るが色が抜けたようになる。
結局のところ絵文字を綺麗に表示するには、<span> で囲んでセレクタが効くようにするか画像に置き換えるかになりそう。
参考になるかもしれないパッケージはこのあたり。