やばい臭いのするCSSコード(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社エンジニアの「?」を「!」に。原著者の許諾を得て翻訳・公開いたします。CSSというタイトルでCSSに潜むアンチパターンについての記事を公開しました。その後4年が経過し、記事の内容についての考えは今も変わっていませんが、さらに追加すべきリストが増えました。繰り返しますが、これらはあくまでコードから立ち上るやばい臭いという兆候であり、これがあるからといって必ずしも絶対的な悪手ではないことにご注意ください。ユースケースによっては全面的に容認できることもあるかもしれません。それでもやばい臭いが残ることに変わりはありませんが。リンク先は日本語版です)」とは何かをおさらいしておきましょう。コードの臭い(または悪臭)とは、コンピュータプログラミングにおいてソースコードにより深刻な問題が潜んでいる可能性をうかがわせる何らかの兆候を指す。Fowler曰く「コードの臭いとはシステム内のより深刻な問題につながりやすい表面的な兆候である」。他の観点として、法則と品質に基づく方法がある。「臭いとは、基本的な設計法則に反し、設計の品質が損なわれていることを示す、コード内の特定の構造である」。通常、コードの臭いそれ自体はバグではなく、技術的に誤っているわけでもなければ、現在のプログラムの機能を損なっているわけでもない。コードの臭いは、将来において開発速度を低下させたりバグや機能不全などのリスクを増加させる、設計上の弱点を指す。コードの悪臭は、技術的負債をもたらす要素の存在を示すことがある。Martinはコードの臭いのリストを、ソフトウェアの技能に役立つ「価値体系」と呼んでいる。コードの臭いは技術的に誤っているとは限らないものであり、単にリトマス試験紙として有用であるということです。@extendを使っている最初のトピックは期待どおりうまく短くまとめられました。筆者は@extendには副作用と落とし穴があると長年主張し続けてきましたが、今こそ@extendをコードの臭いリストに加えたいと思います。@extendは別に絶対悪ではありませんが、多くの場合悪手です。@extendは疑いの眼差しを持って取り扱いましょう。@extendが引き起こす問題はさまざまですが、以下のようにまとめられます。Gzip圧縮は同じコードが繰り返されていると圧縮がよく効くため、mixinなどで繰り返しが多い方が圧縮率は高まります。Sassのextendがあるクラスを見つけると、そのすべてのインスタンスを@extendするため、アホみたいに長いセレクタチェーンが生成されます。ソースの秩序はCSSの命であり、プロジェクトでセレクタがあっちこっちに動き回るような事態は常に避けるべきです。@extendは、精密に解きほぐして追わなければならないSassの複雑さを覆い隠してしまいます。セレクタのクラスを複数使うアプローチなら、すべての情報をマークアップの中核に配置できます。クラス名を&で結合しているSassでもうひとつ言っておきたいのは、次のように&でクラス名の文字列を結合する手法についてです。}}上のSassから以下のCSSが生成されます。bold;}この手法の明らかなメリットは、無精できるという点です。fooという名前空間を1度書けば済むので、コードは間違いなくDRYになります。ここには、ソースコード内にfoo-barという文字列が存在しなくなってしまうというデメリットが潜んでいます。foo-barという文字列をコードベースから検索するなら、HTMLかさもなければコンパイル済みCSSを検索しないと見つけられません(それもプロジェクトにコンパイル済みCSSをチェックインしていればの話ですが)。ある日突然、.foo-barというスタイルをコードから探し出すことが非常に困難になっていることに気付かされます。筆者は、CSSを省略せずに書く(ロングハンド)方法を好んでいます。クラスを&でリネームするよりもクラスを検索する方がずっと多いので、検索性の方が筆者にとって重要です。Sassの文字列結合を激しく多用するプロジェクトに参加することがあれば、コードを追うのが大変になるだろうとだいたい想像がつきます。Sassのsourcemapは有用ではないかという反論もあるかと思います。.nav__itemというクラスを探すなら、nav.scssファイルを開くだけでよいというわけです。残念なことに、これはいつもうまくいくとは限りません。詳しくお知りになりたい方は、筆者のscreencastをご覧ください。backgroundのあいまいなショートハンド最近筆者が他に議論したことといえば、backgroundショートハンドの文法ぐらいです。詳しくは関連記事をご覧いただくとして、ここでは簡単に以下のようにまとめてみました。#f43059;}以下を期待して上のCSSを書いているとします。#f43059;}これがコードの臭いのもうひとつの事例です。前者のCSSが使われていると、開発者がほぼ常に後者を意図していたとしても、そのとおりになるとは限りません。後者は単に背景色を設定または変更するだけですが、前者は背景画像や位置や添付ファイルなどをリセットしたり設定を取り消したりすることもあります。私はこうしたbackgroundのショートハンドがプロジェクトで使われているのを見た瞬間、いつかきっとプロジェクトで問題が発生するという嫌な予感がよぎります。Mozillaドキュメントから以下を補足します。IDセレクタ、クラスセレクタ、タグセレクタのうち最も右に現れるセレクタをキーセレクタと定義します。スタイルシステムによるルール分類よりキーセレクタとは、実際に対象を指定してスタイルを与えるセレクタのことです。キーセレクタは、いま作業している開き波かっこ{の直前にあるものだけとは限りません。次のCSSをご覧ください。{}上のCSSにあるキーセレクタは、以下の4つです。.foo.bara.btn仮にこのコードベースを採用して.btnがどう展開されるかをチェックすると、次のような出力になる可能性がありえます。{}CSSのひどさはさておき、ここで問題にしたいのは.btnが繰り返し定義されている点です。ここから次のことがわかります。ミュータブルなCSSによって.btnクラスが異なる結果を出力する可能性がある筆者がこんなCSSを目にしたら、ボタン表示をどう変えても広範囲に渡って影響が生じ、ボタンのスタイルがどこから来ているのかを正確に追うことがきわめて難しくなるという事実をただちに悟るでしょう。何をどう変えても、画面のあちこちで大量の連鎖反応が引き起こされます。これこそがミュータブルCSSの重大な問題のひとつです。BEM↓などの手法を用いて、重複のない完全に新しいクラスを作成しましょう。{}上のCSSのキーセレクタはいずれも重複していません。他のコンポーネントのファイルで使われているクラスこの問題は上と一見似ていますが、根本的に異なります。他のコンポーネントのファイルで使われているクラスを見つけたら、それはコードの臭いの兆候です。前述のコードの臭いでは、同じキーセレクタのインスタンスが複数あることを問題にしましたが、こちらはそうしたセレクタがどこに潜んでいるかを問題にしています。Rupertから寄せられた疑問をご覧ください。}コンテキストに応じてスタイルを変える必要がある場合、追加のCSSをどこに置くべきでしょうか。thingのスタイルを設定するファイルに置くべきか?コンテキストを制御するファイルに置くべきか?次のCSSがあるとしましょう。{}はどのファイルに配置すべきでしょうか。答えは「.btnのあるファイルに配置すべき」です。スタイルは、可能な限り(キーセレクタなどの)主題に基いてグループ化すべきです。上の例では.btnが主題であり、実際に扱う対象です。.modalは.btnのコンテキストに過ぎないため、ここで.modalにスタイルを設定することはまったくありません。要するに、.btnのスタイル設定を他のファイルに書き出すべきではありません。collocation)」に集約されます。使うボタンのすべてのコンテキストは1か所にまとめる方がずっと便利です。プロジェクトですべてのボタンのスタイルをざっくりと把握したいとき、私なら_components.buttons.scssを開くだけで済むことを期待します。他のファイルをあれこれ開きたくはありません。しておけば、全ボタンのスタイルを新しいプロジェクトにそっくり持っていくのが非常に楽になります。重要なのは、認知上のオーバーヘッドを和らげられる点です。ほんのわずかなスタイル変更のために、テキストエディタで10個もファイルを開かなければならないときの気持ちは皆さんもよくご存知でしょう。した事態を避けることができます。スタイルは主題に基いてファイルにグループ分けしましょう。スタイルの設定対象がボタンであれば、それがどんなCSSであれ、_components.buttons.scssにまとめるべきです。簡単な秘訣として、「今自分が設定しているのはxのスタイルか、それともyのスタイルか」を自問自答するとよいでしょう。xのスタイルを設定しているのであればx.cssに保存すべきですし、yのスタイルを設定しているのであればy.cssに保存すべきです。BEMミックスここまで書いておいてこう言うのも何ですが、私は前述のCSSはまず書きません。私なら実際にはBEMミックスを使うでしょう。これは、また別の疑問への回答です。**/}上のように書く代わりに、次のように書きます。}この第3の新しいクラス.modal__btnは、次のような感じでHTMLに適用されます。modal__btn">Dismiss</button></div>これがBEMミックスと呼ばれる手法です。ここではモーダルダイアログに属するボタンを参照する第3の新しいクラスを導入しています。この手法ならコードの置き場所で悩まずに済みますし、ネストを避けられるのでコードを特殊化せずに広範囲に適用でき、かつ.btnクラスの繰り返しを避けられるので動作の改変も防止できます。CSSの@importCSSの@importについては、単なるコードの臭いどころか、むしろはっきりバッドプラクティスであると主張いたします。重要なアセットであるCSSダウンロードのパフォーマンスが大きく損なわれ、必要なタイミングより読み込みが遅れてしまいます。@importでCSSがダウンロードされるときのワークフローを単純化すると、以下のような感じになります。HTMLファイルを読み込み、そこからCSSファイルがリクエストされるCSSファイルが読み込まれ、そこから別のCSSファイルがリクエストされる最後のCSSファイルが読み込まれるページのレンダリングが開始される仮に@importを1つのファイルに固めたとしたら、ワークフローは次のような感じになるでしょう。/>要素を2つ使うべきです。この方法ではカプセル化がわずかに損なわれます(CSSファイルの依存関係をすべて扱える方がありがたいでしょう)が、それでもパフォーマンス面でずっと有利です。HTMLファイルを読み込み、そこからCSSファイルがリクエストされるCSSファイルが2つとも読み込まれるページのレンダリングが開始されるそういうわけで、前回の「コードの臭い」リストに2項目を追加しました。筆者の「コードの臭い」リストには、筆者が常日頃から直面している問題が盛り込まれています。願わくば皆さまもこうした問題を避けられますように。コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。enno.jpを運営。実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。Storageを使ってはいけない(翻訳)#Tags#会社紹介#自社サービス#勉強会#Rails#PHP#デザイン#実績#週刊RailsウオッチCONTACTお気軽にご相談ください。(翻訳)CONTACTTechRachoでは、パートナーシップをご検討いただける方からのご連絡をお待ちしております。お気軽にご意見・ご相談ください。