みなさんこんにちは。teratail開発チーム デザイナーの平井優です。
Webサービスの制作において、
そんな便利なCSSなのですが、
今回は、
CSSを設計することの重要性
CSSはとてもシンプルかつ学習コストも低く、
しかし、
- 予測していなかった箇所のスタイルが崩れる
- 思った通りにスタイルが反映されず、
新しい記述で上書きをしてCSSが煩雑になる - 期待する場所以外のスタイルが変わってしまい、
過去のCSSを修正せざるを得ない - ファイルの肥大化により、
どこを編集したらいいのか分かりづらい - 既存のスタイルを利用すれば更新は必要ないのに、
重複したスタイルを定義してしまう - ...
etc
いかがでしょうか、
CSS設計を行う上で意識すること
後で困ることのない、
- 予測しやすい
- 機能追加・
見た目の変更・ 修正を行う際に 「どのスタイルが変更されるのか」 または 「どのスタイルは変更されないのか」 が理解できる状態。 - 保守しやすい
- 既存のCSSのリファクタリングをできるだけ行わずに、
新しい見た目や機能を追加できる状態。 - 再利用をしやすい
- 汎用的なスタイルは、
定義したCSSの形を変えずに、 どのような場合でも複数箇所で使い回すことができる状態。 - 拡張しやすい
- 機能の追加・
修正などの拡張をすることを前提として、 他のどの開発者がアサインされたとしても低学習コストでソースコードを理解し、 サイトの拡張ができる状態。
設計が破綻しやすいCSS
次に、
- HTMLの構成に依存している
- スタイルの打ち消しを使用している
- 詳細度によるスタイルの上書きを多用している
HTMLの構成に依存している
以下のようなナビゲーションリストを実装し、a
タグに対してスタイルを定義しました。とりあえず、
<ul class="navigation">
<li><p><a>link1</a></p></li>
<li><p><a>link2</a></p></li>
</ul>
.navigation li p a {...}
数日後、p
タグを削除するマークアップに変更する機会がありました。この変更により、a
タグに対してスタイルが適用されません。そのため、
<ul class="navigation">
<li><a>link1</a></li>
<li><a>link2</a></li>
</ul>
.navigation li a {...}
上記のようなことを繰り返していては、
以下のような実装であれば、
<ul class="navigation">
<li>
<p><a class="navigation-link">link1</a></p>
<a class="navigation-link">link2</a>
</li>
</ul>
.navigation-link {...}
極端な例でしたが、
<div class="navigation">
<a class="navigation-link">link1</a>
<a class="navigation-link">link2</a>
</div>
スタイルの打ち消しを使用している
以下のような見出しの実装があったとします。上下の余白や下線を適用させたくない場合を考えてsimple
というクラスで、margin: 0;border: none;
という打ち消しの指定をしています。
<h2 class="heading simple">シンプルな見出し</h2>
...
<h2 class="heading">デコレーション見出し</h2>
...
.heading {
font-size: 40px;
font-weight: bold;
margin-top: 10px;
margin-bottom: 10px;
border-bottom: 2px solid black;
}
.simple {
margin: 0;
border: none;
}
こういったケースでは、
<h2 class="heading">シンプルな見出し</h2>
...
<h2 class="heading decoration">デコレーション見出し</h2>
...
.heading {
font-size: 40px;
font-weight: bold;
}
.decoration {
margin-top: 10px;
margin-bottom: 10px;
border-bottom: 2px solid black;
}
CSSの記述が2行分削減されました。この範囲だけ見ると小さいものではありますが、
詳細度によるスタイルの上書きを多用している
詳細度とはCSSプロパティを適用させる上での優先度のことで、
- !important
- style属性に記述されているCSS
- IDセレクタ
- classセレクタ・
属性セレクタ・ 擬似クラス - 要素セレクタ・
擬似要素 - ユニバーサルセレクタ
例として、#content
に含まれるp
タグに対して、
p {color: black;}
#content p {color: gray;}
<p>黒にしたいテキスト</p> <!-- 表示:黒 -->
<div id="content">
<p>グレーにしたいテキスト</p> <!-- 表示:グレー -->
</div>
p
タグには元々黒色にするような指定を行っていたので、#content
というIDセレクタを用いることで詳細度を上げて上書き対応しました。
そして数日経った後、red
という文字色を赤くするための汎用クラスを定義し、content
IDの中のp
タグに適用させました。
.red {color: red;}
<p>黒にしたいテキスト</p> <!-- 表示:黒 -->
<p class="red">赤にしたいテキスト</p> <!-- 表示:赤 -->
<div id="content">
<p class="red">赤にしたいテキスト</p> <!-- 表示:グレー -->
</div>
ところが、#content
に含まれるp
タグのみグレーで表示されていました。
プロジェクトが長期的に運用され、
teratailで、
- 参考:cssを指定しやすいhtmlのidの付け方
- https://
teratail. com/ questions/ 19872
キーワードは「コンポーネント化」
CSSは、
このリスクを回避するために効果的な手段として、
たとえば、
![図1 「ボタン」のコンポーネント化のイメージ 図1 「ボタン」のコンポーネント化のイメージ](/assets/images/dev/serial/01/js-foundation/0009/thumb/TH800_001.png)
図1のように
OOCSS
OOCSSでは、
構造(structure)と見た目(skin)の分離
「構造」
先ほどの
<a class="button button-contact">お問い合わせ</a>
/* ボタンの共通プロパティ */
.button {
border-radius: 3px;
box-shadow: 0 1px 1px 0 rgba(0,0,0,.14),0 2px 0px -3px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
text-align: center;
}
/* お問い合わせボタン固有のプロパティ */
.button-contact {
background-color: blue;
}
コンテナー(container)と内容(content)の分離
HTML要素や構造、
h1 {...}
上のように要素セレクタを限定して書いてしまうことはせず、
先述のアンチパターン
.title {...}
また、
#mainColumn .textLink {
color: blue;
text-decoration: underline;
}
#sideColumn .textLink {
color: blue;
text-decoration: underline;
}
次のようにすることで、
.textLink {
color: blue;
text-decoration: underline;
}
当然のように思われるかもしれませんが、
最後に
いかがでしたでしょうか。今回はCSSを書くにあたって
ただ、