メンテナンス性に優れ、拡張性を備えたCSSを書くために -メンテナブルCSS
Post on:2016年4月21日
メンテナンス性に優れ、拡張性を備えたCSSを書くための「MaintainableCSS」を紹介します。
あるスタイルを修正する際に他に影響を与えてしまわないか、せっかく書いたコードが先祖帰りしないか、似たページをつくる時にコードを再利用するのに問題はないかなど、全部はもちろん個々でも非常に参考になると思います。
以下、各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様に許可を得て翻訳しています。
メンテナブルCSSにすることのメリット
- モジュール化、カプセル化
- スタイルはあなたの許可なしで、他のスタイルの影響を受けません。
- どんなデザインの要件でも
- あなたの必要に応じて完全にフレキシブルです。
- ツールは不要
- もしあなたが望むなら、ツールを使うこともできます。
- 学ぶのが簡単
- このガイドを見て、読んでください。
- どんな大きなプロジェクトでも
- 小さいプロジェクトでも大きいプロジェクトでもメンテナブルCSSは助けになります。
- 実践はすぐにできて簡単
- すぐに始めることができ、1つを実践するだけでもOK。
プロジェクト全体をアップグレードする必要はありません。 - 詳細度の問題はなし
- 詳細度による優先順位の問題は心配ありません。真っ白なカンバスにCSSを自由に書いてください。
- ステイトの管理は簡単
- 要素の状態でスタイルを変更するのに頭を悩ます必要はありません。
- 先祖帰りの心配はなし
- 既存のスタイルを変更する時、ほかに影響がないか心配する必要はありません。
- どんな大きさのチームでも
- 一人でも、100人のチームで有用です。
- セマンティックなHTMLとCSS
- メンテナブルCSSはセマンティックはHTMLとCSSを採用しています。
- パフォーマンスに優れたCSS
- コンベンションによるフラットで効率的なセレクタ。
- 冗長なコードを見つけるのは容易
- 冗長なコードを簡単に見つけて、削除しましょう。
- A/Bテストと容易なアップグレード
- モジュールを利用してテストすることを望みますか? メンテナブルCSSはこれを容易にします。
1. はじめに
メンテナブルCSSはあなたとあなたのチームがメンテナンス性に優れ、モジュール化されたスケラーブルなCSSのコードを書くことへのアプローチです。
これは例えば、あるプロパティを変更した際に他の要素に影響を与えてしまう心配がない、せっかく書いたコードが先祖帰りしない、デベロッパとして私が新しい特徴を引き起こすことを望むのを意味します。
ダウンロードするものは何もありません
メンテナブルCSSはあなたがダウンロードすることができる何かではありません。大規模、小規模のWebサイトのCSSを書くのに役立つ原則とガイドのセットです。
「メンテナブル」は何を意味しますか?
メンテナブルなコードであることの意味は、モジュール単位で編集することができ、問題が起きてもそのモジュールだけが原因で、他のモジュールは心配する必要がありません。心の平和を提供するコードを書くことが可能です。
「スケラーブル」は何を意味しますか?
スケラーブルなコードとは拡張性を備えたコードで、メンテナンス性に優れています。もし既存のスタイルを編集する時に、コードがぐちゃぐちゃになってしまうようであれば、あなたはこれに共感するでしょう。
「モジュール」は何を意味しますか?
モジュールとは別個の、独立したユニットで、複雑な構造を構成するために他のモジュールと組み合わせることができます。例えばあなたの部屋にあるベッド、机、テレビ、時計はモジュールで、使いやすい部屋を構成するモジュールの集まりです。
もしあなたがユニットの1つを取り除いても、残りのユニットは機能します。ベッドで寝るために、机は必要ありません。Webサイトで考えると、ヘッダ、フッタ、プロダクトリスト、記事などがすべてモジュールであると考えることができます。
誰のため?
もしあなたが今までにCSSを管理することにおいて苦労を経験したことがあるなら、あなたが抱えた問題を避けるのを助けることができます。1人でも100人のチームにとっても有用なアドバイスを見いだすと思います。
難しいの?
私はメンテナブルCSSを学ぶことは非常に簡単である、と言うでしょう。20分くらいで一通り読んで、その後すぐにルールを適用することができます。私が間違っていると思ったら、どうか知らせてください 🙂
2. セマンティック
- 要約
- 見た目や振る舞いからでなく、目的や役割に基づいて名前をつける
説明
セマンティックなHTMLとは、単にわたし達が使う要素についてではありません。リンクのためにaタグ、表のデータのためにtableタグ、文章のためにpタグなどを使うことはかなり明白です。
もっと重要なことは、それはCSS(そしてJavaScriptも)が適切に拡張すべき追加のフックを供給するclass名(IDも)についてです。特に考えないでclass名を加えることは簡単ですが、名前の付け方は非常に重要です。
コンピュータ サイエンスにはたった2つ、難しいものがあります、「キャッシュ無効化」と「ネーミング」です。
- Phil Karlton
これは人が人間のコミュニケーションを理解することが上手で、セマンティックではない抽象概念を理解することが下手であるからです。
class名の悪い例
セマンティックでないclass名、セマンティックであるclass名を見てみましょう。
1 2 3 4 |
<!-- 悪い例 --> <div class="red pull-left"></div> <div class="grid row"></div> <div class="col-xs-4"></div> |
このHTMLが何を表しているのかまったく明確ではありません。
1 2 3 4 5 |
<!-- 良い例 --> <div class="header"></div> <div class="basket"></div> <div class="product"></div> <div class="searchResults"></div> |
このHTMLが何を表しているのか、正確に理解できます。私はこのHTMLが表す意図が分かり、そしてどのように見えるかは分かりません。見え方はCSSが責任を担うものです。セマンティックなclass名は、HTMLとCSSの両方に何かを意味します。
わたし達はなぜセマンティックなclass名を使うべきなのでしょうか?
理由: 理解することが簡単になるから
あなたがHTMLあるいはCSSを見ているかに関わらず、あなたが何に影響を与えているか知っています。視覚的なclass名にしてしまうと、それぞれの要素に複数のclass名を与える必要が生まれます。これは維持することが困難です。
理由: レスポンシブ対応サイトを作っているから
スタイルはしばしばビューポートの大きさに基づいて変えることを必要とします。例えば大きいスクリーンではフロートさせ、小さいスクリーンは積み重ねるかもしれません。もし「.clearfix」と呼ばれるclassを使っているなら、小さいスクリーンではclearされないので、紛らわしいでしょう。
もしあなたがセマンティックなclass名を使うのなら、メンテナンスが容易であるようにして、Media Queriesをベースに異なるスタイルを使うことができます。
理由: 見つけるのが簡単だから
もし要素が「.red」「.clearfix」「.pull-left」のように見た目のclass名を使っているなら、あなたのコードのストックからそのコードを探し求める時に、class名が役立つことはないでしょう。しかしclass名がセマンティックであるなら、検索で簡単に見つけることができます。
理由: 想定外の不具合にならないため
もしこれらのclassの1つを修正する時に見た目のclass名があると、そのclassに関連した他のclassも一緒に修正する必要があるかもしれません。そしてこれらの修正が想定外の箇所に問題を与えない自信がありますか?
セマンティックなclass名はユニークなので、それを修正する時には問題のあるモジュールだけで済みます。
理由: アップデートする際の危惧は不要
不具合を修正する時には問題が起きているコードだけを修正するため、他の箇所への影響を恐れる心配は不要です。
理由: 検証を助けるから
テキストを入力したり、ボタンやリンクをクリックしたりなど自動化された機能的なテストで、特定の要素を探す時に役立ちます。もしHTML内のいたるところに見た目のclass名を持っていると、特定の要素に目標を定めてアクションを起こす方法はありません。
理由: メンテナンス性における配慮のため
例えば見出しは常に「heading」のように役割に基づいてclass名をつけるのであれば、大規模な方法で再びHTMLに触れなくて済むでしょう。スタイルは変化するかもしれませんが、その時はCSSだけ更新すればよいです。
理由: ユーティリティのclassがデバッグ時にノイズを増やすから
要素をデバッグする時、デバッグする時のノイズになるCSSのセレクタが複数あります。
理由: パフォーマンス増加のため
これは非常に小さい利益ですが、要素ごとにclass名が1つだと、HTMLのコードはより少なくなります。見た目のclass名と一緒にすると多数のclass名が必要になってしまいます。
理由: 再利用のルールを破るため
もしセマンティックなclass名を使わないなら、おそらく再利用のルールを破っているでしょう。このことは次に詳しく述べます。
結論: セマンティックについて
セマンティックなclass名は、メンテナブルCSSの基礎となるものです。これなしでは他のすべてはほとんど意味をなしません。
3. 再利用
- 要約
- スタイルを再利用しようとしないでください。デュプリケーション ファースト(最初に複製)するアプローチを採用してください。
スタイルを再利用しようと試みることは、なぜそれほど問題でしょうか。
理由: 再利用がセマンティックを破るため
もしあなたが極めて小さいclass名を再利用するのであれば、「2. セマンティック」のすべての問題に遭遇します。既にそうしなかったら、今すぐ前の章に戻ってください。
理由: 再利用が肥大化を起こすから
もしあなたが残らずすべての規則を再利用するのであれば、「red, clearfix, pull-left, grid」のようなclass名はHTMLの肥大化に導きます。
1 |
<div class="clearfix pull-left red etc"></div> |
肥大になってしまうと、維持することが難しくなり、パフォーマンスが低下します。
理由: デバッグが困難になるから
要素をデバッグする時、デバッグする時のノイズになるCSSのセレクタが複数あります。
理由: 問題を抱えるスタイルに価値はないから
もし「<div class="red">」とするなら、「<div style="color: red"」を使った方がましです。こっちの方が明示的です。しかし指定を混ぜることは望まないので、インラインで指定することも望みません。
理由: ブレイクポイントに基づいて変化するから
レスポンシブ対応サイトを構築するということは、ビューポートのサイズに基づいて要素に異なるスタイルを適用することを意味します。2カラムのグリッドを作るとします。
- 大きいスクリーンで50px、小さいスクリーンで20pxのpaddingを持たせ、
- font-sizeは3em、2emをそれぞれに設定します。
- そして小さいスクリーンでは、それぞれのカラムが積み重なるようにします。
最小のclass名に「.grid, .col, .pd50, .pd20, .fs2, .fs3」を使い、これらの仕様を達成することができますか?
1 2 3 4 |
<div class="grid"> <div class="col pd50 pd20 fs3 fs2">Column 1</div> <div class="col pd50 pd20 fs3 fs2">Column 2</div> </div> |
これはうまくいかない例です。この形式で実装するには「.fs3large」のようなばかげたclass名を必要とします。このことは、メンテナンス性における問題の氷山の一角に過ぎません。
代わりにスタイルを再利用しない、セマンティックなマークアップを見てみましょう。
1 2 3 4 |
<div class="someModule"> <div class="someModule-someComponent"></div> <div class="someModule-someOtherComponent"></div> </div> |
この記述は、Media Queriesに定義する3つの要素に必要とされる6つのCSS宣言を含めたシンプルなタスクです。
理由: スタイルはステータスに基づいて変化するから
「<a class="padding-left-20 red" href="#"></a>」の:hover, :focus, :active時に、18pxのpadding、細いボーダー、グレーの背景、テキストのカラーを変えるなど、どのように実装しますか?
短い答えですが、それはできません。自身によって引き起こされた問題を直さなければならないのを避けようとしてください。
理由: 見た目のclass名は意味をもたないから
class名の「.red」を例に見てみましょう。
赤い背景? 赤いテキスト? 赤いグラデーション? それとも赤の色合いを意味しますか?
理由: ユーティリティのclassを更新することはすべての例に当てはまるから
これは良いように思えるかもしれませんが、そうではありません。あなたがそうするつもりはなかった変更を適用してしまうことになります。先祖返りを考えてみてください。「.red」を変更するより、「.red2」をつくる方が安心できるかもしれません。これは明らかにメンテナンスするのが楽しくありません。
理由: セマンティックではないclass名は見つけにくいから
「.red, .col-lg-4, .large」のような見た目のclass名がついた要素をHTMLテンプレートから探した時、おそらく多くの検索結果が表示されるでしょう。セマンティックなclass名を使うなら、検索結果は1つです。もし1つ以上の検索結果がでたら、使い方が間違っています。
もし本当にスタイルの再利用を望むならどうでしょう?
それは極めてまれですが、スタイルを再利用することに意味があることがあります。その場合はセレクタでコンマを使って再利用してください。
例えば異なるモジュールあるいはコンポーネントに赤いテキストを持つことを望んだとします。
1 2 3 4 5 6 |
/* colours.css */ /* red text */ .someSelector, .someOtherSelector { colour: red; } |
もしセレクタがルールからはずれてしまうようであれば、よくあるリストと重複から取り除きます。これは非常に注意深くおこなってください。パフォーマンスのためではなく、便利さのためです。恩恵があるかは場合により異なります。
Mixinsはどうですか?
CSSプリプロセッサは素晴らしいMixinsを作成することができ、あなたにとってベストに思われることを可能にします。
しかしユーティリティのclass名と同じようにどんな場合でも増殖するので、Mixinsの更新には気を使わなければなりません。既存のMixinsに触ることに怯えてしまい、冗長性とメンテナンス性を無視して新しいMixinsを作成するかもしれません。
また、Mixinsはスタイルの多くのパラメータ・条件適用・宣言で、非常に複雑になってしまうことがあります。そして複雑なものは維持することが難しいです。
Mixinsを使ったとしてもスタイルを修正する時、あなたは検索をしなければならないでしょう。Mixin名も同様にしてください。
パフォーマンスはどうですか?
私は手に届くところに統計値を持っていませんが、自信をもって時期尚早な最適化を練習することは賢明ではないと言うことができます。100KB以上の非常に大きなCSSがあるとします。
第一に、私はあなた自身のために数KBを省くかもしれないと思います。第二に、パフォーマンスを改善することへの代わりの方法があります。そして第三に、おそらく保持性の欠如のために冗長なコードを持っています。
ここでエネルギーを使うのはほとんど価値がなく、CSS全体より1つ2つの画像の方がはるかに大きな影響があると考えてください。
DRY原則に違反していますか?
例えば「float: left;」を再利用しようとした場合、JavaScriptのオブジェクトでバリアブルな名前を再利用することに類似しています。それはDRY原則に違反していません。
結論: 再利用について
再利用とDRYはソフトウェア・エンジニアリングで重要な原則です。しかしCSSの話になると、それは皮肉にもメンテナンスを難しくします。スタイルの規則を再利用するのを避けてください、そしてCSSを保守するのが容易になる利益を得てください。
4. ID
- 要約
- スタイルするためにIDをフックとして使用しないでください。
わたし達はなぜCSSのためにIDを使うべきではありませんか?
理由: 特定性の問題のため
IDは詳細度によってclass名に勝ちます(参考: selector's specificity)。そのため、class名のセレクタで簡単にIDセレクタのスタイルより優先させることができません。
このことは、HTMLに追加の意味を提供する方法を必要とするときに問題が生じます。
1 2 3 4 5 6 7 |
#someModule { color: red; } .someModule-override { color: blue; } |
要素にIDとclass名の2つを与えたら、idの赤が適用されます。
1 2 3 4 5 6 7 |
.someModule { color: red; } .someModule-override { color: blue; } |
2つともclass名であれば、後に定義された青で上書きされます。
でもIDは時々必要とされますか?
時々、IDを使うことは必要です。
例えばフォームのコントロールでは、IDによってラベルにリンクされます。そしてページ内リンクにもIDを使用します。これら両方ともユーザエクスペリエンスを改善するものです。スタイルのためではなく、追加の行動のための適切な使い方です。
結論: IDについて
スタイルのためにIDをフックとするのは避けてください。しかし他のことのために必要とするなら、IDを使ってください。ID名はclassと同様にネーミングのルールに固執してください。
5. コンベンション
コンベンションはエンジニアの間で論争の種ですが、最も重要なことは読みやすさと一貫性です。メンテナブルCSSにおけるコンペンションを見てみましょう。
1 2 |
/* Square brackets denote optional parts */ .<moduleName>[-<componentName>][-<state>] {} |
モジュールに関する検索結果の例です。
1 2 3 4 5 6 7 8 9 10 |
/* module container/root */ .searchResults {} /* components of a module */ .searchResults-heading {} .searchResults-item {} /* state: such as AJAX loading */ .searchResults-isLoading {} |
これらのclass名はそれぞれがセマンティックです。モジュール、コンポーネント、ステイトがダッシュですべて区切られ、それぞれ単語の最初を大文字で表記したキャメルケースで書かれます。
わたし達は、このコンベンションがこの論文のすべてで使われるのを見るでしょう。
6. モジュール
モジュールとは何ですか?
モジュールとは別個の、独立したユニットで、複雑な構造を構成するために他のモジュールと組み合わせることができます。例えばあなたの部屋にあるベッド、机、テレビ、時計はモジュールで、使いやすい部屋を構成するモジュールの集まりです。
もしあなたがユニットの1つを取り除いても、残りのユニットは機能します。ベッドで寝るために、机は必要ありません。Webサイトで考えると、ヘッダ、フッタ、プロダクトリスト、記事などがすべてモジュールであると考えることができます。
コンポーネントとは何ですか?
モジュールはコンポーネントで構成されています。コンポーネントなしでは、モジュールは不完全か、あるいは壊れています。例えばベッドはフレーム・脚・マットなどで構成されています。
ロゴのモジュールは、イメージやテキストやリンクから構成されています。イメージなしではロゴは壊れており、リンクなしではロゴは不完全です。
モジュールとコンポーネント
何がモジュールで、何がコンポーネントであるか決めることは慎重を要します。例えばヘッダはモジュールです、そしてロゴやナビゲーションなどを含んでいます。これらはコンポーネント、あるいはモジュールでしょうか?
実はそれはあまり重要ではありません。それを決めるにはあなたの経験を使うことができます。私の場合、最近のプロジェクトでヘッダのコンポーネントであることはロゴ、そしてヘッダの中でモジュールあるナビゲーションにとって意味をなしました。
最終的にはあなただけがあなたのプロジェクトの必要条件を理解します。コンポーネントをモジュールと交換して問題があるか、逆がいいのかは非常に簡単なことです。
モジュールの作成
モジュールをつくってみましょう。
プロダクトのタイトルと削除ボタンで構成された買い物カゴのHTMLです。
1 2 3 4 5 6 7 8 9 |
<div class="basket"> <h2 class="basket-title">Basket</h2> <div class="basket-item"> <h3 class="basket-productTitle">Product title</h3> <form> <input type="submit" class="basket-removeButton" value="Remove"> </form> </div> </div> |
上記HTMLのためのセレクタです。
1 2 3 4 5 6 7 8 |
/* module container */ .basket {} /* components */ .basket-title {} .basket-item {} .basket-productTitle {} .basket-removeButton {} |
モジュールとコンポーネントが非常に分かりやすいと思います。
モジュールの2番目のバージョンの作成
今度はチェックアウト時の買い物カゴをつくるとします。
タイトルは「あなたのバスケット」から「注文一覧」に変わり、プロダクトを削除する機能が必要かもしれません。
これをつくる際に、さきほどの買い物カゴを再利用したい誘惑にそそられるかもしれませんが、決して再利用しないでください。「3. 再利用」で学んだように多くの理由が問題です。
メンテナブルCSSでは再利用の代わりに、モジュールを複製することを勧めます。注文のようのclass名「.orderSummary」をつけ、複製します。
7. ステイト
特にリッチなユーザインターフェイスを提供しようとした時、モジュールやコンポーネントはステイトに基づいたスタイルにする必要があります。ステイトには、表示されている時、非表示の時、ローディング時、ローディング終了時などがあります。これをするためには、わたし達はさらにclass名を加えなくてはなりません。
ステイトの要約
モジュールを「myModule」と名付け、次のように「isActive」classを適用してみます。
1 |
<div class="myModule isActive"></div> |
しかし「isActive」は多くの異なるモジュールで使われることはありそうです。アクティブであることが意味することはモジュールによって異なることがあり、そのことはメンテナブルCSSの基本的な規則を壊します。
そのためステイトは、モジュール(あるいはコンポーネント)にハイフンを用いて接続させます。
ステイトをモジュールに適用
新しいモジュールを見てみましょう。
1 |
.myModule {} |
このモジュールを接頭辞にして、ステイトを繋げます。
1 2 3 4 5 |
.myModule-isDisabled {} .myModule-isActive {} .myModule-hasProducts {} .myModule-isHidden {} .myModule-isLoading {} |
HTMLで使うと次の通りです。
1 2 3 |
<div class="myModule myModule-isDisabled"> <p class="myModule-title">The title</p> </div> |
ステイトをコンポーネントに適用
次のように「myModule-title-isDisabled」をコンポーネントに適用します。
1 2 3 |
<div class="myModule"> <p class="myModule-title myModule-title-isDisabled">The title</p> </div> |
これは、簡単ですね。
8. バージョニング
長期に渡り、Webサイトを展開する時、バージョン対応のモジュールは役立ちます。例えば、モジュールの2つのバージョンでA/Bテストを行い、どちらに効果があるか見ることを望むかもしれません。あるいはブランドをリフレッシュさせるかもしれません。
あなたのコードに多数のバージョンを用意するために、HTMLとCSSを再利用する誘惑にかられることがあります。メンテナブルCSSではメンテナンスビリティを助けるために、ユニークな名前で同じ物をつくることを勧めます。
1 2 3 4 5 |
/* existing module */ .someModule {} /* new version of module */ .someModuleVariant2 {} |
あなたがしなければならないことは、ユニークなモジュール名で2つの別個のモジュールをつくることです。そしてそれぞれは影響を与えずに、独立して修正することができます。
sponsors