先日Whalebirdのバージョン0.5.0をリリースした.このリリースに,アプリのテーマカラー変更が含まれている.
中身はElectronの上でVue.jsが動いているだけなのだが,どうやってテーマを変更するか,だいぶ悩んだので書いておく.
クラスをすげ替える
普通に作っていて,「あーここはスタイル変えたいな」と思ったら,大抵の場合はつけるクラスをすげ替えるだけでいける.
<template> <div :class="customizedClass"> </div> </template> <script> export default { data () { return { customizedClass: 'hoge' } } } </script> <style lang="scss" scoped> .hoge { background-color: #000000; } .fuga { background-color: #ffffff; } </style>
こんな感じにしておいて,customizedClass
を fuga
に切り替えたりすればクラスが変わる.
これによりデザイン変更が可能だ.
ただ,テーマカラー変更のように,全ての画面において,全体の色を変えたいという用な要望の場合,いろんな画面でこういった切り替えを作らなければならないので,あまり現実的な解とはいえない.
また,クラスの挿げ替えは,用意されたクラス1から用意されたクラス2というような変更しかできない. 例えば将来的に「ユーザが好きなテーマを作れる」というような機能を実装したくなった場合に,まったく対応できなくなる.
style属性を上書きする
クラスをすげ替えるのではなく,cssのスタイル定義を直接コンポーネントに当てることもできる.
<template> <div class="hoge" :style="style"> </div> </template> <script> export default { data () { return { style: { 'background-color': '#ffffff' } } } } </script> <style lang="scss" scoped> .hoge { background-color: #000000; } </style>
というようにしておけば,hoge
クラスがあたった上で,style属性で background-color
を上書きできる.
確かにこれなら,ユーザが定義したカスタムテーマという拡張が入った時にも対応できそうだ. ただし,やはり背景変更が必要な全てのコンポーネントでstyle属性の上書きが必要になる.上書きが必要ということは,その都度,style属性に指定する値を取得・計算する必要があるという意味でもある.
これはかなり面倒くさい.
css変数を使う
上記の改造で,background-color
を直接上書きするのではなく,css変数をVue.js側から操作するパターン.
<template> <div :class="customizedClass"> </div> </template> <script> export default { data () { return { style: { '--background-color': '#ffffff' } } } } </script> <style lang="scss" scoped> .hoge { --background-color: #000000; background-color: var(--background-color); } </style>
と,これだけ見ると,先ほどと大差ない感じはする.
ただし,これがcss変数になっている点で大きく変わることになる. 今,コンポーネント内のstyle定義は全てscopedにしている.そのため,この中で定義したクラス等はこのコンポーネント内でしか使えない.
しかし,これを全てのコンポーネントのベースとなる場所で,scopedを外してやったらどうか.
即ち,全てのコンポーネントの親となる App.vue
のようなものを用意してあり,
<template> <div id="app"> <router-view></router-view> </div> </template> <script> export default { } </script> <style lang="scss"> body { font-family: 'Noto Sans', sans-serif; } </style>
みたいな定義になっているとする.この中で先ほどのcss変数を使ったらどうか.
<template> <div id="app" :style="style"> <router-view></router-view> </div> </template> <script> export default { data () { return { style: { '--background-color': '#ffffff' } } } } </script> <style lang="scss"> body { font-family: 'Noto Sans', sans-serif; } #app { --background-color: #000000; background-color: var(--background-color); } </style>
としておく.で,子コンポーネント側では,
<template> <div class="hoge"> </div> </template> <script> export default { } </script> <style lang="scss" scoped> .hoge { background-color: var(--background-color); } </style>
としておく.
--background-color
はcss変数で,unscopedなstyleの定義となっているので,App配下のコンポーネント内の全ての場所で使える.
つまり,styleの更新はApp.vueだけで行えば良くなる.
子コンポーネントのスタイルを全て変数を使った形式に書き換えておく必要はあるが.
これなら,ユーザ定義のカスタムテーマを導入した際にも,Appで変数を変更できるようにしておくだけで済む.
というわけでダークテーマが出来上がった
ちなみに色彩のセンスはまったくないので,Mastodonの公式で使用している色をかなり真似ている.
そのうちテーマ色もカスタマイズできるようにするので,センスある人は自分の好きな色に変えてください.
こちらが参考になった.