CSS設計を今更勉強してみた
動機
今の案件では既に設計/実装されたものが出てくる
個人開発ではそれほど必要性を感じない
→なあなあにしてきて案件で使っているRSCSSのよさがいまいちわからん
内容
https://images-na.ssl-images-amazon.com/images/I/51WKOuhrzlL._SX394_BO1,204,203,200_.jpg
よいCSS設計とは?
CSS設計手法概要紹介
→復習だと思って聞いていただけると
CSSの難しいところ(なぜCSS設計が必要なのか)
いいところ
文書の構造とスタイルの分離(タグに直で書いていたスタイルを一括管理!)
わるいところ
すべてがグローバルスコープ
中規模以上の開発をする際には「壊れやすすぎる」(=想定外のスタイル衝突)
CSS開発当時との状況の違い
表示コンテンツの複雑化
CMSなどの変更不可HTML/CSSの存在
ページ数の増加
動的なスタイル変更
→スタイリングがお互いに干渉し合う恐怖に耐えながらの開発
解決策(干渉しない仕組み)
CSS設計←今日はここ
抽象化する/分けるための方法論
カプセル化されたDOM(Element.attachShadow() でLight DOMに追加)
https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F537488%2Fa5e8a7d4-e7c4-e03e-634d-a5aaf9a80547.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=d6f84d556e98b4fd60774484882901c5
jsフレームワークによるscoped css
→基本的には状況に応じてこれらを併用する形になるが、どちらにせよCSS設計的な思考は必要
CSS設計概要
CSS設計の共通性質
抽象化する
分ける
UI設計についての概念だが、CSS設計と親和性が高く、理解の助けになる
https://cdn.codegrid.net/2017-atomic-design/img/hierarchy.png
1. 予測できる
スタイリングが予測できる
スタイリングの影響範囲が予測できる
2. 再利用できる
適切な抽象化、分離
3. 保守できる
追加要素が既存要素に影響を与えない
4. 拡張できる
サイト/チームの拡張に耐えうるわかりやすいルール
おまけ:CSSの基本単語
ゴールを達成するための8つの規則・工夫
1. 特性に応じてCSSを分類する
ベース/レイアウト/モジュールなど
「ly-」「el_」など接頭辞をつける場合もある
2. コンテンツとスタイリングが疎結合である
要素型セレクタを使用しない
属性セレクタの特定の値に依存させない
3. 影響反映がみだりに広すぎない
スコープを絞る
影響範囲の広いCSSに含めるスタイリングは最小限に留める
4. 特定のコンテキストにみだりに依存していない
5. 詳細度がみだりに高くない
基本的にクラスセレクタを使用する
スタイリング目的でIDセレクタを使わない
6. クラス名から影響反映が想像できる
モジュールの子要素には、モジュールのルート要素のクラス名を継承させる
titleというクラス名だと汎用的で使い回せるイメージ
hogeModule_titleという名前であれば範囲がわかりやすい
7. クラス名から見た目・機能・役割が想像できる
title→page-title
8. 拡張しやすい
マルチクラス設計を採用する
シングルクラス設計
<a class="el_btnTheme" href="#">標準ボタン</a>
<a class="el_btnWarning" href="#">色違いボタン</a>
マルチクラス設計(OOCSS, SMACSS, BEM, PRECSS)
<a class="el_btn hp_theme" href="#">標準ボタン</a>
<a class="el_btn hp_warning" href="#">標準ボタン</a>
→8つの規則・工夫を持ったいろんな設計手法が発生
具体的な設計手法
OOCSS(Object Oriented CSS) 設計手法の基礎、多くの設計手法の基礎になった(手法ってよりは思想寄り?)
1. ストラクチャとスキンの分離→ストラクチャは共通化されやすい、スキンは差がでやすい
ストラクチャ:width, height, padding, margin
スキン:color, font, background, box-shadow, text-shadow
code: oocss.html
<main id="main">
<button class="btn general">標準ボタン</button>
<button class="btn warning">キャンセルボタン</button>
</main>
code: oocss.css
/* ストラクチャ */
.btn {
display: inline-block;
width: 300px;
max-width: 100%;
...
}
/* スキン */
.general {
}
.warning {
}
2. コンテナとコンテンツの分離
どこでも使用できる汎用的なパーツをブロックのように積み上げていく→使い回せる
code: 従来.html
<div class="entry"> ←コンテナ
<h2>見出しのテキスト</h2> ←コンテンツ
<p>テキストテキストテキスト</p>
</div>
<div class="news">
<h2>見出しのテキスト</h2>
<img src="/blog/2015/10/exsample.jpg" alt="画像" >
<p>テキストテキストテキスト</p>
</div>
code: 従来.css
.entry h2 {
color: red;
font-weiht: bold;
}
.news h2 {
color: red;
font-weiht: bold;
}
code: OOCSS.html
<div class="entry"> ←コンテナ
<h2 class="entry-title">見出しのテキスト</h2> ←コンテンツ
</div>
<div class="news">
<h2 class="entry-title">見出しのテキスト</h2>
</div>
code: OOCSS.css
.entry-title {
color: red;
font-weiht: bold;
}
→厳格なルールはないので単体での運用をするものではないが、基本的な考え方として有効
SMACSS(スマックス:Scalable and Modular Architecture for CSS) 5つのカテゴリについて規則を定めているデザインガイドライン
1. ベースルール(=標準のスタイル)
主に要素型セレクタ使用(あまり具体的なスタイルは指定しない)
IDセレクタ/クラスセレクタ使用不可、!important使用不可
リセットCSSも含む
code: baseRule.css
body {
background: white;
}
letter-spacing: 0;
}
a:visited {
color: navy;
}
2. レイアウトルール(=ページのエリア分け、見た目以外)
クラス名にl-、layout-などをつける
code: layoutRule.css
.l-main {
width: 70%;
}
.l-fixed .l-main {
width: 600px;
}
.l-grid {
width: 48%;
margin: 0 0.5%;
}
3. モジュールルール(=使い回せるパーツの具体的な見た目)
子モジュールの名前は親モジュールの名前をプレフィックスでつける
code: レイアウトとモジュールを組み合わせた例.html
<div class="l-container-12"> ←レイアウト
<div class="l-grid-06"> ←レイアウト
<div class="box"> ←親モジュール
<p class="box-text">box1</p> ←子モジュール
</div>
</div>
<div class="l-grid-06"> ←レイアウト
<div class="box"> ←親モジュール
<p class="box-text">box2</p> ←子モジュール
</div>
</div>
</div>
なるべく要素型セレクタを使用しない
セマンティックな要素にのみ要素型セレクタを使う
要素型セレクタを使用する際は子セレクタを使用する
特定のコンテキストにみだりに依存しない
サブクラスを使用する
code: 非推奨.html
<div class="l-main">
<div class="search">~</div>
</div>
<div class="l-sub">
<div class="search">~</div>
</div>
code: 非推奨.css
/* subの際の上書き */
.l-sub .search {
hoge
}
code: 推奨.html
<div class="l-main">
<div class="search">~</div>
</div>
<div class="l-sub">
<div class="search search-vertical">~</div>
</div>
code: 推奨.css
/* subの際の上書き */
.search-vertical {
hoge
}
4. ステートルール(=既存のスタイルの上書き/拡張)
レイアウトやモジュールに割り当てる
JavaScriptに依存する
接頭辞はis- ex) is-acitve, is-hidden
モジュール固有の場合はモジュール名を継承 ex) is-box-active
5. テーマルール(=サイト全体の見た目の雰囲気を統一)
ダークテーマとかのイメージ
→BEMほど厳格ではないものの、ガイドラインとして優秀。他の手法と組み合わせることも多い。
BEM(ベム:Block, Element, Modifier) クラスセレクタを使用し、詳細度は均一
要素の違いはアンスコ、複数単語はハイフンで区切るなどかなり厳格に決められている
Block(=どこでも使い回せるパーツ)
レイアウトに関するスタイリング(周りに影響を及ぼすpositionやfloat, marginなど)はしない
命名規則
block, block-name
ex) menu, global-nav
見た目ではなく、なんのためなのかを表す単語を使用 ex) red-textではなく、error
BlockはBlockを含めることができる
https://programan.s3.amazonaws.com/uploads/content_image/bem2.png
Element(=Blockを構成し、Blockの外では独立して使用できないもの)
命名規則
Block名+アンスコ✕2+Element名
block__element, block-name__element-name__element-name
ex) menu__item, global-nav__link-item
https://programan.s3.amazonaws.com/uploads/content_image/bem1-3.png
code: BlockとElement.html
<div class="search"> <!-- Block -->
<input class="search__input"> <!-- Element -->
<input class="search__btn"> <!-- Element -->
</div>
Modifier(=Block/Elementの見た目/状態/振る舞いを定義するもの)
Block/Elementのオプション
命名規則(一般)
適用したいBlock/Element名+アンスコ+Modifier名
block__element_modifier, block-name__element-name_modifier-name
ex) menu__item_actived, global-nav__link-item_actived-and-focused
命名規則(キーと値の組み合わせ)
適用したいBlock/Element名+アンスコ+Modifierキー+アンスコ+Modifier値
block__element_key_value, block-name__element-name_modifier-key_modifier-name
ex) menu__item_text_large, global-nav__link-item_color-theme_caution
パターン
真偽値
状態:disabled, focused, actived
キーと値
見た目:size_s, theme_caition
振る舞い:directions_right-to-left, position_bottom-right
その他命名規則パターン block-name__elem-name--mod-name, blockName__elemName_modKey_modVal など →かなり細かいルール設定があるので、大変ではあるが従っていれば良い感じ
SMACSS ✕ BEMみたいな感じ
6つのグループに分類
1. ベース
2. レイアウト
3. モジュール
4. ヘルパー
5. ユニーク
6. プログラム
RSCSS(Reasonable System for CSS) CSS設計のアイデアセット:覚えやすく、導入コストが低い
Components(=UIパーツ)
命名規則
最低2つの単語をハイフンでつなぐ←ハイフンがあったらComponents
ex) .like-button, .article-card, .rico-custom-header
https://rscss.io/images/component-example.png
Elements(=Componentsを構成する子要素)
命名規則
単語一つ
複数単語の場合は区切り文字なしでつなぐ
ex) .item, .field, .firstname
子セレクタ(>)の使用を推奨(今の案件ではマスト)←クラス名を短くできる!!!
要素型セレクタは非推奨
https://rscss.io/images/component-elements.png
Variants(=見た目や機能のバリエーション)
命名規則
先頭にハイフン←linuxコマンドとかと似ててわかりやすい
ex) .-short, .-disabled
https://rscss.io/images/component-modifiers.png
Helpers(=プロパティをオーバーライド)
命名規則
先頭にアンスコ
ex) ._unmargin, ._center, ._hidden-pc
→とにかくわかりやすくて実用向き、scopedCSSとの相性が良い
まとめ
RSCSSわかりやすい
CSS設計自体の重要性もさることながら、モジュール(=コンポーネント)単位での開発っていう概念は必須
モジュールの粒度は経験が必要
コメントでもらった参考リンク
おまけ:CSSの基本単語
セレクタの種類
単純セレクタ
要素型セレクタ ex) p{}
全称セレクタ ex) *{}
属性セレクタ ex) a[href="http://hoge"]{}
クラスセレクタ ex) .my-class{}
IDセレクタ ex) #my-id{}
疑似クラス ex) a:visited{}
疑似要素 ex) a::before{}
結合子
子孫結合子 ex) div p
子結合子 ex) div > p
兄弟結合子
隣接兄弟結合子 ex) div + p
一般兄弟結合子 ex) div ~ p
カスケーディング(=同じ要素&プロパティに違う値の場合どれを優先するか)
1. 重要度
!importantなど
2. 詳細度
1. IDセレクタ
2. クラスセレクタ、属性セレクタ、疑似クラス
3. 要素型セレクタ
3. コードの順序
後が強い
リセットCSS
ハードリセット系CSS
完全リセット
ノーマライズ系CSS
ある程度デフォルトスタイルを活かす