最近、1プロジェクトの中に複数サービスがあり、サービスによってコンポーネントの色やサイズを調整したいという要望がありました。
このとき、CSS設計をどのように行うべきかを考えた結果のまとめになります。
注意
他によい方法があるかもしれませんので、検討時に選択肢の1つとして考えていただければと思います。
また、よりよい方法を知っているよという場合、是非その方法を教えていただけるとうれしいです。
実装について
例
わかりやすいのでボタンで考えてみます。
サービスのテーマカラーのボタンを設置したいとします。
このとき、btn--service
をクラスに指定すれば、指定した色のボタンが実装できるとします。
そうなると下記のようなコードになります。
.btn {
...
&--service {
background-color: #f00;
}
}
<button class="btn btn--service">テキスト</button>
よく見慣れた形です。
複数サービスの場合
複数のサービスがあった場合、どうなるでしょうか。
すぐに思いつくのが、それぞれ別のクラス(modifire)を作成する方法でしょうか?
.btn {
...
&--serviceA {
background-color: #f00;
}
&--serviceB {
background-color: #0f0;
}
}
<button class="btn btn--serviceA">テキスト</button>
<button class="btn btn--serviceB">テキスト</button>
このような形になるかと思います。
(※本来であれば、サイズ用のクラスなどがあるかと思いますが、ここでは省略しています)
では、次は問い合わせボタンも定義していくとします。
その際、問い合わせボタンの色は、サービスごとで違う色にしたいとします。
先ほどと同じように対応するのであれば、下記のようになるかと思います。
.btn {
...
&--inquiryServiceA {
background-color: #f00;
}
&--inquiryServiceB {
background-color: #0f0;
}
}
<button class="btn btn--inquiryServiceA">テキスト</button>
<button class="btn btn--inquiryServiceB">テキスト</button>
これでも問題はないのですが、そのサービスの中で使用するのに、わざわざそのサービス名がついたクラス名をつけるのって面倒ではないでしょうか?
scssを別にする
では問題を解決するために、scssを別にしてみます。
serviceA/_btn.scss
.btn {
...
&--inquiry {
background-color: #f00;
}
}
serviceB/_btn.scss
.btn {
...
&--inquiry {
background-color: #0f0;
}
}
こうなれば、これをそれぞれのサービスの共通scssでimportすればいいだけです。
でも、ボタンコンポーネントがサービスごとに散ってしまいました。
やはりボタンはボタンで固まっていて欲しくないでしょうか?
mixinという方法もありだとは思いますが、毎回作成するのも少し面倒なので、別の方法を考えてみました。
そこで、提案するのが、色などを管理するtheme.scss
をサービスごとに作成し、ここで管理するという方法です。
対応方法
_btn.scss
.btn {
...
&--inquiry {
background-color: $inquiry_color;
}
}
background-color
の指定を変数にしました。
ここで宣言した変数を、各サービスで上書きしていくことになります。
base/_theme.scss
// 指定がなかった場合のデフォルトを指定しておく
$inquiry_color: #fff !default
デフォルトとなる色などを指定しておきます。
今は必要ないかもしれないですが、今後上書きの必要がない場合に使用していきます。
serviceA/_theme.scss
$inquiry_color: #f00;
serviceA用の色を指定します。
serviceB/_theme.scss
$inquiry_color: #0f0;
serviceB用の色を指定します。
serviceB/layout.scss
@import "base/theme";
@import "serviceA/theme";
@import "btn";
importの順番が重要になります。
まず、デフォルトのテーマを読みこんで、その後にサービスAのテーマを読み込んでいます。
その結果、base/theme
で指定されたものをベースにし、その後serviceA/theme
で指定されたもので上書きすることになります。
※パスは必要に応じて修正してください
serviceB/layout.scss
@import "base/theme";
@import "serviceB/theme";
@import "btn";
こちらに関してはserviceAと同様になります。
まとめ
以上が対応方法になります。
このようにサービスごとに変化させたい値を変数で切り出し、読み込み時に上書きしていくことで、コンポーネントをまとめたままでも、サービスごとのModifire(パターン違いのクラス)を定義する必要がなくなります。
もちろん、普通にModifireとして定義した方がいい場合もあるので、常にこの方法の方がいいということはないと思います。
状況に応じて、このようなCSS設計も選択肢の1つに加えていただければと思います。