scopedを前提とした小~中規模CSS設計を考える
2019.10.01
案件ではNuxtを利用することが多く、大仰なCSS設計は逆に作業効率を悪化させる。コンポーネントごとに閉じる世界なので、命名規則をがちがちに決めて冗長なクラス名を付けたくない。ということで今自分が思っているCSSの設計粒度を、メンバーとすり合わせる意味でもまとめておく。
前提
案件でいつもこんな流れでやっているなーという以下条件を前提として考えています。
- Nuxt.jsを利用。小~中規模のウェブサービス(サイト)構築案件が対象。
- 基本的にCSSはscopedでvueファイルに記載
- ノーマライズ、リセットCSSなどはconfigなどで読み込んでおく
コンポーネント分けについてはこの記事では言及しないです。あれはあれで考え始めると本当に沼が深い。
HTMLとはなにか
こういう哲学的な問いはふわっとしているしいろいろな意見があるけど、一応原点に立ち返りたいのでメモ。
HTMLとは構造化された文章であり、 構造には意味がある。
決してdivでパズルを組むのがHTMLの役割ではない、という点だけ認識が取れていればOKです。
- 構造上無意味なdiv, spanの利用は避ける(装飾のためだけに使用するのは避ける)
- section, main, nav, figureなど、HTML5で再定義された要素を使用してセマンティックに要素を配置する
- 要素はなるべく少なくできる方が良い(場合によるけど)
要素をラップするときは必要なのでdivを使っても良いと思っています。むしろそういう使用方法に限定しておく方がなんのためのdivなのかわかりやすくて良いし。
シンプルに書こう
「シンプルに書く」というと難しく聞こえるかもしれないけど、 明示的に簡単に書く 、ということを意識するとイメージが付きやすいかもしれないです。
情報量を削ぎ落とすこと ≠ シンプルに書くということは注意したいところ。
特に自分以外の人間が見ても分かるかどうかが重要です。
「他人が見ても分かる」 は 「どこに何が書いてあるか分かりやすい」 と言い換えることができると思います。
その他こういったことも意識できると良いかも。
すべての知識はシステム内において、単一、かつ明確な、そして信頼できる表現になっていなければならない。
具体的な記述方法
ではどうやって書くか、具体例を出しつつ列挙していきます。
- セクションにユニークなクラスを付ける(コンポーネント名をつけるイメージ)
- 名前はそれ単体でわかるものに極力したい
- OK例 : hero, newsなど機能や役割が明示される名前
- NG例 : information1など順序に依存したり、役割が分からない名前
- 名前はそれ単体でわかるものに極力したい
- セクション配下の命名は基本的に一般的な名詞で良いかなと思います
- Newsの配下であれば、
.list
や.item
のようなわかりやすいクラス名で良い - ただし、きちんとscssを構造化し、 直下セレクタ
>
を使用する- scssの構造化は見やすくするための大事なポイント
- Newsの配下であれば、
- クラスを書く順序もなるべく意識してHTML側と合わせる
- そのクラスに付けるプロパティ → レスポンシブ対応用メディアクエリ → 子要素、など、書く順番をルールにしておくとわかりやすいと思います
- 同じようなプロパティがあっても、やたらとmixinにしたりしない
- 省力化より明示することを優先する
- 逆に、色指定やフォントの指定などは変数にしておいて記法のブレを無くす
<!-- 例:ヒーローエリアの下に、ニュースとSNS埋め込みの2カラム表示 -->
<template>
<main class="cout-wrap">
<section class="col-wrap wrap-center">
<div class="hero col-lg-10">
<h1>Lorem Ipsum</h1>
<p>Lorem Ipsum is simply dummy text. </p>
</div>
</section>
<section class="col-wrap wrap-center">
<div class="news col-lg-5">
<h2>News</h2>
<ul class="list">
<li class="item">
<div class="date">YYYY.MM.DD</div>
<div class="title">newstitle</div>
</li>
<li class="item">
<div class="date">YYYY.MM.DD</div>
<div class="title">newstitle</div>
</li>
<li class="item">
<div class="date">YYYY.MM.DD</div>
<div class="title">newstitle</div>
</li>
</ul>
</div>
<div class="sns col-lg-5">
<h2>SNS</h2>
<div class="twittermodule">
<iframe>...</iframe>
</div>
<div class="facebookmodule">
<iframe>...</iframe>
</div>
</div>
</section>
</main>
</template>
/* scoped内に書くcssの構造 */
.hero{
> h1{
hogehoge
}
> p{
hogehoge
}
}
.news{
> .list{
> .item{
> .date{
hogehoge
}
> .title{
hogehoge
}
}
}
}
.cout-wrap
や .col-wrap
、 .col-lg-10
などはレイアウトのためのクラスです。
またそれは別途記事にしますので、ここではスルーで。
HTML要素に直接プロパティを指定している箇所もありますが、任意にクラスを付けるイメージです。
scopedの恩恵を最大限利用しています。一般的な名詞はクラス名にすべきではないという声も大きいと思いますが、scopedと直下セレクタを利用して影響範囲を区切るようにします。
共通化するためには
共通化したいクラスはどうするんだ、という問題がありますが、それは Atomic DesignのAtomsをどうするか、という問題と最終的に紐付いてくるな、 というのが自分の考えです。
コンポーネントを階層化して分けて、それぞれを読み込んでいくと、末端はスタイルを指定するプロパティの塊みたいになっていきます。
Atomsレベルのボタンコンポーネントなんかは、ほぼスタイル指定くらいしかすることないですもんね。
そういったプロパティは、クラスを作成し、グローバルで読み込んでおく、というのが良さそうです。
vueファイルとしてコンポーネントするのも分かりやすいですが、小~中規模案件であまりコンポーネント化が激しくなると負担の方が増えてしまいます。
やらないで欲しいこと
以下はアンチパターンです。レビューしてて思ったかなり初歩的なことを列挙しています。
- 同じクラスに当てるプロパティをばらばらの場所に書かない
- width,flexなどのプロパティ名をクラス名で使わない
- 略語を使わない
- infoなど自分も使いがちだけどやめる
- btnなどもやめる
- 何を示しているのか分からないクラスはつくらない
- mini_infoなどのクラス名を使わない。
- sp,tbなどのクラス名を使わない。
- :nth-childやfirst-of-typeは同じ要素の羅列のときにつかう
- 違う役割の要素を、親要素内の順番で指定する、というような意味で使わない
- 同じことを何度も書かなくて済むようにする
- メディアクエリでデバイス幅ごとに同じことを書く、というようなことは避ける
今回は小~中規模と絞ってCSS設計について書きました。
以下のような記事も参考しました。
OOCSS、BEM、SMACSS、FLOCSS、RSCSSを比較して自分にあった設計思想をみつける | Black Everyday Company
冗長なクラス名が苦手なので、こういった考え方を自分なりに咀嚼して導入していきたいです。
なにかご意見やご感想あればぜひお寄せください。