最近Web業界で活躍されている方々をTwitterで見つけたらフォローしています。
デザイナーやエンジニアやマーケター、または経営層の方まで、担当業種に関係なく有益な情報を発信している人たちのツイートは新しい考え方に出会えたり、制作のモチベーションに繋がりますね。(意識高め)
自分も、Webサイトをコーディングしている世の中のエンジニアの方々の役に立つ情報を発信するため、今回はCSS設計についての自分なりの考え方を紹介したいと思います。
ここに掲載する内容は僕自身の独自で解釈であり、一般的な考え方ではないかもしれません。
また登場する言葉についても誤りがあるかもしれません。
ある程度Webサイトのコーディングに慣れてきた人、度重なるサイトの更新があってもCSSが破綻しないようにしたい人などに読んでいただけると何か参考になるかと思います。
また今回の解説ではSASSを利用しますが、使い方やインストールついては説明を省きます。
上記の点に注意して続きをお読みください。
CSSは昔から「保守が難しい」と言われています。
なぜ難しいのか、ざっくりと言うとCSS自体がとても簡単で単純なものだからだと思います。
誰でも簡単に変更ができてしまう為、何も制約がない状態でCSSファイルを更新し続けると色々な困りごとが出てきます。
よくある例をあげると、、
これらはサイトを構築した段階で設計を考えずにコーディングした場合や、当初はしっかりと作っていても設計を理解せずに、または無視して無秩序に更新していくうちに、小さなホコリのように少しずつ溜まっていきます。
ホコリが目に見えるほど一杯になってくると更新時に問題が出てきます。
この問題を解決するために、今度は新しいクラスを追加したり、さらに優先度の高いセレクタで上書きすることになります。
こうなってくると負の連鎖が始まり、何とも更新のし辛いサイトが出来上がります。
この問題は一度CSSを整理しなおさないと解決できませんが、積もり積もったホコリを掃除するのは想像以上に労力が必要です。
そうなる前にCSSはきれいに保つ必要があります。
こうしたCSSの問題を防止し負担のかからないコードを維持するために、Webサイトの構築時にCSS設計を考える必要があります。
設計を考える上で重要な2つのポイントあります。
ファイル構造と命名規則です。
Webサイトはボタン、見出し、タイポグフィ、カード、メインビジュアル、ヘッダーなどなど、一般的なデザインパーツを組み合わせて作られています。
今回、デザインパーツを3つカテゴリに分類します。
上記の分類に従ってディレクトリやファイルを作ります。
sass
┣ theme.scss … 全てのSASSファイルをまとめる
┣ _config.scss … SASS変数を宣言するCSS
┣ _mixin.scss … ミックスインを宣言するCSS
┃
┣ block … ブロックパーツのディレクトリ
┃┣ _b_header.scss … ヘッダー用のCSS
┃┣ _b_footer.scss … フッター用のCSS
┃┗ _b_navigation.scss … ナビゲーション用のCSS
┃
┣ component … コンポーネントパーツのディレクトリ
┃┣ _c_button.scss … ボタン用のCSS
┃┣ _c_header.scss … 見出し用のCSS
┃┗ _c_card.scss … カード用のCSS
┃
┗ utility … ユーティリティパーツのディレクトリ
┣ _u_margin.scss … マージン用のCSS
┗ _u_color.scss … カラー用のCSS
SASSのディレクトリ以下に分類ごとのディレクトリを作成し、さらにパーツの種類ごとにファイルを用意します。
ファイル名は頭に分類名の頭文字を書くことでどこに分類されているかを明確にします。
これはFLOCSSと呼ばれるCSSの設計思想をもとにしており、分類方法をオリジナルなものに変更しています。
重要なのはデザインパーツをカテゴリ分類し、編集ファイルをわかりやすくすることです。
分類はサイトの規模に応じて、最適な粒度にするのが良いと思います。例えばボタンは1つのCSSファイルで管理していますが、バリエーションが多いようならば、バリエーション毎にファイルを用意しても良いと思います。
一般的なコーポレートサイトだと上記のような粒度で分けるのが丁度良いと思います。
まずクラス名の命名規則を考える前に、セレクタはクラス名と属性のみを使用することを前提にしましょう。
要素名を使うとマークアップの変更に対応できなくなるので、スタイルを当てる要素には必ずクラス名をつけましょう。
また、ID名を利用するとセレクタの優先順位が高くなり、スタイルの上書きが一気に難しくなるので避けるべきです。
クラス名を考える時のポイントで、
コンポーネントは汎用性があることが重要で、特定のコンテンツ名をつけてしまうと、別のコンテンツ内でそのパーツを使う際にややこしくなります。これはサイト構築後の更新などで起こりうる問題です。
基本的にコンポーネントはサイト内のどこで使われても問題のない名前にしておくのが賢明です。
メンテナブルなCSS設計の話から逸れてしまいますが、ページのパフォーマンス面でCSSのセレクタは階層が深いほどレンダリングが若干遅くなります。
これはブラウザのレンダリング時の1プロセスの過程で、HTMLファイルのクラス名や要素などが、CSSファイルのどのセレクタとマッチングしスタイルが当てられるのかをブラウザが計算する処理時間に影響し、階層が浅いほど早く計算処理が済みます。
興味のある方は「CSSのマッチング処理」を検索してみてください。
これは意見が分かれそうですが、少しタイプ時間が長くなっても単語は略さない方が良いと思います。(長すぎる場合は使用する単語を考え直す)
わかりやすさと、認識違いの可能性をなくすことがより重要であると思います。
上記のポイントを気をつけた上でさらに命名規則を考えましょう。
ファイル構造を考えた時にSASSファイル名の頭に分類名の頭文字を入れましたが、クラス名も同様に分類名の頭文字を入れましょう。また、SASSファイル名をクラス名に使うことでCSSがどこのファイルに書かれているかわかるようにします。
1 2 |
<!-- 分類の頭文字 + SASSのファイル名 + ナンバリング --> <h1 class="c-headline1">株式会社アウラ</h1> |
上記のクラス名は「分類名の頭文字(この場合はcomponentの”c”)」 + 「SASSのファイル名」 + 「見出しパーツのナンバリング」で命名しています。
この場合、CSSは[sass/component/headline.scss]に書かれていることがわかります。直感的でわかりやすいですね。
また命名規則を利用せずともソースマップを設定していればブラウザの検証画面で編集ファイルはわかりますが、sassのみではなく、postcssなども併用している場合などはソースマップがうまく機能しない場合もあります。クラス名で直感的にファイルを見つけられるようにしておくことは様々な開発環境でも柔軟に対応しやすくなると思います。
BEMは他の命名規則に比べクラス名が長くなりがちですが、クラス名が他のパーツと被ることがなく、パーツ内での関係性も明白になります。
1 2 3 4 5 6 7 8 |
<article class="c-card1"> <figure class="c-card1__image"> <img src="image01.jpg"> </figure> <h2 class="c-card1__headline">見出し</h2> <p class="c-card1__paragraph">本文が入ります。本文が入ります。</p> <a class="c-card__anchor">続きを読む</a> </article> |
上はブログ一覧の各記事のデザインパーツを想定しています。「c-card1」をルートとして、各要素がクラス名から「c-card1」のデザインパーツということがわかります。
上の例では小さなコンポーネントなのでピンとこないかもしれませんが、複数のコンポーネントを組み合わせたデザインパーツを作る場合に効果がでます。
また、SASSを利用することでセレクタの記述も省略できる上、視覚的にパーツの単位がわかりやすくなります。
1 2 3 4 5 6 7 8 |
/* カードデザイン1 */ .c-card1 { &__image { ~~ } &__headline { ~~ } &__paragraph { ~~ } } |
個人的にBEMで唯一やっかいなのが「Modifier」です、通常のBEMのルールに従って、あるコンポーネントのバリエーション違いを作る場合、SASSの継承やミックスインの機能を利用すると思います。
ただし、継承は扱いが難しく、ミックスインはコンパイルした時の記述量が多くなる上にバリエーションを想定して書くと全てのコンポーネントをミックスインありきで書くことになってしまいそうです。
それを回避するためにModifierを独自にカスタマイズし、マルチクラスを利用することにします。
1 2 3 4 5 6 7 8 |
<article class="c-card1 __vari1"> <figure class="c-card1__image"> <img src="image01.jpg"> </figure> <h2 class="c-card1__headline">見出し</h2> <p class="c-card1__paragraph">本文が入ります。本文が入ります。</p> <a class="c-card__anchor">続きを読む</a> </article> |
先にでてきた「c-card1」コンポーネントを例に、上記のようにコンポーネントのルートの要素に「__vari1」というクラスを追加します。(独自ルールでModifier用のクラスは「__(アンダーバー2つ)」を頭につけます)
SASSは以下のように書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* カードデザイン1 */ .c-card1 { $this: &; &__image { ~~ } &__headline { ~~ } &__paragraph { ~~ } /* Variation 1 */ &.__vari1 { #{$this}__headline { ~~~ } #{$this}__paragraph { ~~~ } } } |
マルチクラスを利用して、バリエーションに追加でスタイルをあてます。「$this」の変数を宣言することでマルチクラスの以降も見出しや本文などのパーツのクラス名を指定できます。
マルチクラスを利用するときの問題として、もし「c-card1」の要素に、例えばユーティリティのクラスなど、別のデザインパーツのクラス名がある場合、Modifier用のクラス名はどのパーツに対してのものかわからなくなります。
1 2 3 4 5 6 7 8 9 |
<!-- 「__sp_vari1」は「c-margin-section」、「c-card1」どちらのModifier? --> <article class="c-margin-section __sp_vari1 c-card"> <figure class="c-card1__image"> <img src="image01.jpg"> </figure> <h2 class="c-card1__headline">見出し</h2> <p class="c-card1__paragraph">本文が入ります。本文が入ります。</p> <a class="c-card__anchor">続きを読む</a> </article> |
こういう場合はクラス名を書く時に「|」のような区切り文字を使い、グルーピングをわかりやすくすると明確になります。
1 2 3 4 5 6 7 8 9 |
<!-- 「__sp_vari1」は「c-margin-section」のModifier --> <article class="c-margin-section __sp_vari1 | c-card |"> <figure class="c-card1__image"> <img src="image01.jpg"> </figure> <h2 class="c-card1__headline">見出し</h2> <p class="c-card1__paragraph>本文が入ります。本文が入ります。</p> <a class="c-card__anchor">続きを読む</a> </article> |
ただし、Modifier自体あまり多用はしない方が無難です。
1つのコンポーネントに無理やりバリエーションを増やさず、適切にコンポーネントは増やしましょう。
いかがでしたでしょうか。
CSS設計ということで、今回はファイル構造と命名規則について、普段自分がどう考えてCSSの実装をしているかを紹介しました。
重要なのは「更新のしやすさ(ストレス)」、「効率のよさ(スピード)」、「わかりやすさ(丁寧)」のバランスだと思います。
このバランスはサイトの規模感や携わる人の数で変わってくると思います。サイトの規模が小さかったり、個人で開発する場合は「わかりやすさ」は少なくスピード重視が良いと思いますが、チームで開発する場合は自分以外の全員が理解できるよう丁寧に設計しなければいけません。
ただWebサイトは更新し続けていくものであり、基本的に自分以外の他者が更新することを想定してCSS設計を考えるべきだと思います。