Enduring CSS 03
実装は知恵を得る
最後の章では、大きなCSSコードベースを扱う際に明らかないくつかの困難について考えました。この章では、これらの問題に対処するための既存のアプローチをいくつか検討していきます。
2年間にわたって、私はCSSアーキテクチャとメンテナンスの旅を続けてきました。経験の冒頭近くで、私は賢明な開発者がすべきことをしました。私は賢明な人々がすでに問題をどのように処理していたかを見てみました。
CSSのスケーリングという固有の問題のために、CSSアーキテクチャのアプローチは、太りすぎを解消するやせ薬と同じように見えるかもしれません。見かけの解決策だけを簡単に見つけて、必要なことに正確に収まることを期待します。しかし、問題を少なくとも1回解決するまで、あなたが必要としているものを正確に把握していない可能性があります。
そのアドバイスもここに適用されます。CSSの問題を解決し始めたばかりの場合、ECSSは問題の解決策ではない可能性があります。異なる方法論がそれを提供することを考えてください。
当時、大規模なCSSを扱うための主なアプローチは次のとおりでした:
Yandexが開発したBEM(Block-Element-Modifier) さて、私は今恥ずかしげもなく言いますが、それぞれから要素を盗んできました。しかし、それらのどれも、私が持っていた問題を実際には解決しませんでした。
ECSSに取り掛かる前に、既存のアプローチのそれぞれの長所と短所を簡単に見ていきたいと思います。そうすれば、少なくともECSSに取り掛かる前に、それらによって問題を解決していることを賞賛するでしょう。
OOCSSについて
私が見た既存のアプローチの中で最も広く実践され、最も広く賞賛されたのはOOCSSでした。これは絶え間なく成長しているCSSコードベースに取り組む際に、私が利用した最初のアプローチでした。
OOCSSアプローチの主な議論の1つは、コードの重複を除去し、より保守的なCSSコードベースをもたらすということです。本質的に、あなたはHTML/テンプレートを使用してデザインを素早く作り上げるために、一連のCSS「レゴ」のピースを組み立てます。OOCSSスタイルが書かれたら、あまり大きくしないようにしなければなりません。あなたは可能な限り再利用し、必要な場所を拡張します。
OOCSSを見る前に、いくつかの警告を出さなければありません。
これは、OOCSS、Atomic CSS、または関連する単一責任原則(SRP)アプローチに対する批判ではありません。あなたの目標に応じて異なるアプローチが優先的な結果をもたらすことができるという単なる私の主張です。
私が主張しているアプローチは、すべてのCSSスケーリングの問題に対する万能薬であると示唆しているわけではありません。万能薬はありません(存在しない)。
レスポンシブなウェブデザイン、OOCSSのアキレス腱
私が思うOOCSSアプローチの2つの最大の問題点は次のとおりです。
レスポンシブなWebデザイン
頻繁な設計変更と継続的なメンテナンス
なぜ私がこれらの2つの問題を検討する価値があると実証できるかを見てみましょう。
レスポンシブ問題
私はAtomic CSS(Atomic Designと混同しないでください)を、n番目の段階としてのOOCSSを表現していると考えます。想像上のAtomic CSSの例を考えてみましょう:
<div class="blk m-10 fr">Here I am</div>
このOOCSS / Atomic CSSの例では、要素の視覚的ニーズが、再利用可能なクラスに分割/抽象化されています。ブロックフォーマッティングコンテキスト(.blk)を設定し、もう1つはmargin(.m-10)を設定し、最後に要素(.fr)のフローティングメカニズムを提供します。従順で簡潔な確かさで。
code:aside
原則として、Atomic CSSは私が考案した最初のアーキテクチャアプローチと非常によく似ています。
それは「PST!」と呼ばれていた位置構造テーマの略語でした。アイデアは以下の通り: セマンティックHTMLクラス/CSSセレクタはありません。その代わりに、ページ上のすべての要素は、その位置、構造、およびテーマによって記述することができます。新しいセレクターは次の利用可能な番号を取るだけです。たとえば、s1、s2、s3、等など。Atomic CSSの場合と同様に、レスポンシビリティなクラスではありませんでしたが、それは形式的なニーズを大きく抽象化する方法でした。 マークアップは次のようになりました。
<div class="p1 s3 t4">Content</div>
Atomic CSSのように、それは簡潔であり、執筆したときに何を呼び出すべきかについて熟考することはありませんでしたが、実際には、このセクションで説明したのと同じ理由により、この実践にはそれなりの問題がありました。
ただし、ビューポートが変更されたときに何が起こるでしょう?10pxのマージンまたはフローティング要素が要らない場合はどうすればよいですか?
もちろん、特定のブレークポイントでいくつかのクラスを作成して処理を行うことができます。たとえばMplus-cc2、 Mplusブレークポイントで色を変更する可能性があります(MplusはここではMediumサイズのビューポート以上です)。しかし、私はこの実践が遅く、面倒だと感じました。
特定のブレークポイントで非常に具体的な変更を行い、それらをHTMLに追加する必要のあるクラスに結び付けることは、不必要に複雑にしていると思います。さらに、必然的に古いSRPクラスのラップになります。オーサリングスタイルシートから不要になった何らかの塊を取り除くためのオーサリングメカニズムは何でしょうか?
メンテナンスと繰り返し
先ほどの例を続けてみましょう。将来的には、製品をより進歩的なレイアウトの仕組みに変更するとします。floatベースのレイアウトからFlexboxベースのレイアウトに移行します。現時点では、メンテナンスに2倍の負担がかかります。マークアップ/テンプレート内のクラスを変更するだけでなく、CSSのルール自体を変更する(または全く新しいルールを書く)必要があります。さらに、floatを使用するとFlexboxで余計なものが使用され、私たちは.frを放置するか(CSSで不必要に存在し続けます)、またはjustify-content: flex-endなどの何かで.frの代わりをします。しかし、特定のビューポートで親のフレックス方向を変更するとどうなりますか?Arrgggghhhh!
https://gyazo.com/0bd2b543c4e0d2c39e1b187791b57fbf
設計が頻繁に変更されたり、別のビューポートでまったく異なるレイアウトをレンダリングする必要がある場合、保守のためのOOCSSアプローチ固有の欠点を確認できますでしょうか?
Atomic CSSは、2013年にSmashing Magazineに掲載されたThierryの記事からかなり発展しました。あなたの達成に応じた、必要なものかもしれません。http://acss.io でプロジェクトをチェックすることをお勧めします。 純粋なOOCSSの例
例としてAtomic CSSを使用することは不公平であり、おそらくOOCSSを公平に表現していないと主張することは正しいでしょう。しかし、OOCSSの標準的な例を得ることは、CSSの作者が信じていることと、それがどのように実装されているかの間に大きな相違があるように思われます。
私はNicoleのオリジナルの例が非常に古く(2009年、レスポンシブWebデザインはまだのものでした)、彼女に聞くことはしなかったので、今日は別の例とアプローチを使用するかもしれないと言うくらいには、それを使うのは嫌でした。
レスポンシブWebデザインでは、構造がスキンである時があります。むしろ、構造は異なるコンテキストで異なることを行い、OOCSSを使ってこれを処理するための純粋な方法はありません。しかし、あなたは審判者となります。
このOOCSSの例を考えてみましょう。まずはマークアップ:
code:example03-01.html
<div class="media attribution">
<a href="#" class="img">
<img src="mini.jpg" alt="Stubbornella" />
</a>
<div class="bd">@Stubbornella 14 minutes ago</div>
</div>
そして、CSS(注意:いくつかのOldIE固有のプロパティ値をここで削除しました):
code:ecss03_01.css
.media { overflow: hidden; margin: 10px; }
.media .img { float: left; margin-right: 10px; }
.media .img img { display: block; }
.media .imgExt { float: right; margin-left: 10px; }
http://ecss.io/images/ch3-1.png
-- WIP --
しかし、このメディアオブジェクトは、300pxのワイドビューポートで別に配置する必要があるかもしれません。その状況で列ベースのレイアウトにするために、メディアクエリを設定することができます。しかし、同じビューポート幅で別のコンテキストで同じ「オブジェクト」を持っているとします。そしてその文脈では、それは列のレイアウトにあってはなりません。推測するには:
1番目のメディアオブジェクトは、300px幅の列ベースのレイアウトである必要があります(これを media1 とします)。
2番目のメディアオブジェクトは、300px幅の行ベースのレイアウトでなければなりません(別のコンテキスト/コンテナ内にあるので、これを media2 と呼びます)。
より多くの懸念を分けるクラスを作ってみましょう。メディアオブジェクトは、特定のビューポートの列レイアウトになります。
code:ecss03_02.css
@media (min-width: 18.75rem) {
.media-vp-small {
/* Styles */
}
}
そのビューポート( media1 )の列にする必要がある要素に追加されるので、必要に応じてクラスを追加して、その変更を行うためにテンプレート/ HTMLに向かう必要があります。
さらに、 media2 は大きなビューポートで異なる背景色を持つ必要があります。その懸念を分ける別のクラスを追加しましょう:
code:ecss03_03.css
@media (min-width: 60rem) {
.draw-focus {
/* Styles */
}
}
必要に応じてそのスタイルを追加するには、HTML /テンプレートに入ります。
ああ、 media1.imgは大きなビューポートではより広い必要があり、マージンはありません。そのために別のクラスを作ることができます:
code:ecss03_04.css
@media (min-width: 60rem) {
.expand-img {
width: 40%;
margin-right: 0!important;
}
}
その変更を行うためにHTML /テンプレートに戻る。
うまくいけば、これはどこに向かうのか分かりますか?メディアオブジェクトが容易にする必要のあるさまざまなシナリオを容易にするために、多くのSingle Responsibility Principle(SRP)クラスが追加されています。
このアプローチでは、応答性の高いコードベースをより保守性の高いものにすることはできませんでした。実際には、かなり反対です。変更が必要なときはいつも、特定の状況のために特定のSRPクラスのために狩りを行い、しばしばマークアップ/テンプレートでHTMLクラスを追加/削除する必要がありました。それは私に質問を熟考させました:
なぜそれはできないのか?
今のところ、あなたは、「デザインが非常に多くの出来事を持っているなら、それは正規化されなければならない。どちらの時点で私はそれが必要ではないはずだと反対します。フロントエンドをコーディングしている人は、デザイナーのクリエイティビティをあまり変えることはできません。彼らは、新しいコンポーネント/モジュール/物が他の人にどのように影響を与えるかについて、自分自身について心配することなく、簡単かつ簡単に新しいデザインをコード化できるはずです。
code:aside
単にコードベースを維持するのが難しいため、プロジェクトの視覚的な変更を防ぐことは、防衛的な立場ではありません。プロジェクトの他の領域に不注意に影響することなく、スピードと予測可能性を備えた新たな視覚的治療法を構築できるはずです。
OOCSSを使用して私のニーズに取り組んだとき、新しいビジュアルを構築するスピードが減り、単一責任主義クラスの数が増えました。多くの場合、クラスはプロジェクト全体で1回または2回だけ使用されます。
急速に変化するプロジェクトでOOCSSを使用すると、しばらくすると、変更が必要なときにこれらの抽象クラスを「無効にする」ことが信じられないほど欲求不満であることがわかりました。彼らが実際にほとんど使用されなかったときに、私は多くの非常に似た抽象クラスを作らなければならなかった。以下のようなユーティリティクラスw10、w15、w20、w25異なる幅の割合についてなどは良いアイデアと作るために明白な抽象化のように思われたが、彼らは最終的に(バック異なるコンテキストで異なることを行うために必要なものの問題に)で設計を反復するために役に立たないと問題があることが判明しました。
2年前、私はDRYコードを説いていた本を書いたが、耐久性のあるプロジェクトに取り組んだ後、それは私にとってより重要になった "デカップリング"です。
大規模で急速に変化するプロジェクトでは、プロジェクトからビジュアルモジュールを簡単に切り離すことができるため、継続的なメンテナンスには非常に重要であり、OOCSSはこのニーズを容易には促進しませんでした。
SMACSSについて
CSS用のScalable Modular Architectureを表すSMACSSは、Jonathan Snookの本書に詳しく述べられています。私はSMACSSの詳細をここには載せません。あなたが見るべきだと思うので、あなた自身でその本をチェックしてください。SMACSSを読むことは、私が自分の挑戦に直面したときに私が噛んできたことをたくさん与えました。そして、私は確かにそれから状態の変化を考える方法など、物事を取った。しかし、SMACSSがなぜ私にとってうまくいかないのかを詳しく説明します。 再び、OOCSSに関する私の意見についての私の警告のように、これはSMACSSの批判ではありません。それは単に私にとってうまくいかなかった部分と、それが自分の問題を解決できなかった理由を強調しているだけです。SMACSSは、ウェブサイトの視覚的側面に関する用語と概念を明確に定義しています。したがって、これらの定義をサポートするために、ベース、レイアウト、モジュール、およびオプションのテーマルール/ファイルが規定されています。たとえば、この推奨ファイル構造を考えてみましょう。
code:tree.sh
+-layout/
| +-grid.scss
| +-alternate.scss
+-module/
| +-callout.scss
| +-bookmarks.scss
| +-btn.scss
| +-btn-compose.scss
+-base.scss
+-states.scss
+-site-settings.scss
+-mixins.scss”
抜粋:Jonathan Snook "CSSのためのスケーラブルでモジュラーなアーキテクチャ"
これらの定義は多くのシナリオで理にかなっていますが、私の場合はそうではありませんでした。私はもっと緩やかなアプローチを望んでいました。これは、私が構築する必要があるものをそれらの視覚的定義に合わせることを考慮する必要はありませんでした。私が構築し維持していたアプリケーションは、しばしばそれらの定義に順守していませんでした。
BEM
私がBEM(Block-Element-Modifierの略)から取り上げた重要なことは、CSSメンテナンスに関して命名規則がどれくらい購入できるかということだけです。
SMACSSのように、私はBEM方法論の内容を十分に説明しようとはしません。しかし、私はキーポイントの「エレベーターピッチ」の説明を与えます。BEMの方法論は、ページの主要な領域を「ブロック」として定義できるという概念を取り入れています。次に、これらの重要な領域は要素で構成されています。次に、ブロックとその要素の関係を、名前を付ける方法で表現することができます。これまでのOOCSSメディアオブジェクトの例を考えてみましょう。BEMアプローチでは、次のようなクラスを使用することがあります。
code:example03-02.html
<div class="media">
<a href="#" class="media__img">
<img class="media__headshot" src="mini.jpg" alt="Stubbornella" />
</a>
<div class="media__attribution">@Stubbornella 14 minutes ago</div>
</div>
この名前付けスキームでは、要素と要素が属するブロックとの関係を明確に伝えることが非常に便利です。さらに、HTMLから離れて、CSSのようなセレクタを見つけたら、
code:ecss03_05.css
.media__headshot {
}
私たちは即座に、これが「メディア」と呼ばれるブロック内に存在する「ヘッドショット」と呼ばれる要素であることを知っています。この名前空間をコンポーネントの一部として使用することで、スタイルを切り離し、適用されたスタイルがOOCSSの主要なバグの一つである「漏出」するのを防ぐことができます。これは間違いなく私が解決しようとしていた問題の正しい方向への一歩でした。
BEMには「修飾語」という概念もあります。モディファイアは、外観に変更を加えるためにブロックに追加されるものです。異なるシナリオで異なるメディアオブジェクトをテーマにしたいとします。これをBEMは次のように容易にしてくれます:
code:example03-03.html
<div class="media media_dark">
<a href="#" class="media__img">
<img class="media__headshot" src="mini.jpg" alt="Stubbornella" />
</a>
<div class="media__attribution">@Stubbornella 14 minutes ago</div>
</div>
BEMドキュメントでは、単一のアンダースコア文字を使用してブロックの修飾語を識別します。この修飾子クラスは、常にブロック名の横に使用する必要があります。たとえば、これを行う必要があります:
<div class="media media_dark">
こうではありません:
<div class="media_dark">
私はこの方法で修飾語を使用することの価値を見ていますが、問題があることが判明しました。スタイリングしていたものは、より伝統的なやり方で異なった振る舞いをする必要があることがよくあったのです。おそらく、ビジュアルは使用されていたコンテキストに応じて、または別のクラスがDOMの上に追加されているかどうかによって表示方法が異なります。もしくは、特定のメディアクエリ条件、実際にそれらのシナリオの任意の組み合わせをするために異なります。私は、発生した非理想的な状況に対処するのに十分な実用的なスタイルを作成する方法が必要でした。それらにスローされたものに関係なく、オーサリングスタイルシートにいくつかの正気を保つためのいくつかの方法。
まとめ
私が見た既存のCSS手法のうち、私はBEMを最大限に活用しました。BEMで感謝するべきことがたくさんあります:
すべての要素が同じ特異性を持ちます。すべての要素にクラスが追加されます。
タイプセレクタは使用されていないので、HTML構造はスタイルに密接に結合されていません。
ブラウザの開発者ツールでDOMツリーを表示しているのか、コードエディタでCSSを表示しているのかにかかわらず、要素の親が何であるかを簡単に判断できます。
しかし、モディファイアの使用は、私のニーズに本当に適合しませんでした。おそらくそれは望ましくはありませんでしたが、私の現実は、ブロック上のいくつかの事実やDOMの側面に応じて、ブロックのスタイルをBEM用語でオーバーライドする必要があることがしばしばでした。
たとえば、既存のロジックがアプリケーション内ですでに決定されているシナリオではcontains2columns、問題のアイテムの上にDOMのようなクラスが追加され、それに基づいて変更をスタイルする必要があるシナリオが存在する可能性があります問題のブロックに直接変更されます。
BEMを使用すると、その事態をどのように処理すべきかを理解する明確な方法を見つけることができませんでした。または、オーサリングスタイルシートにこれらのオーバーライドをどのように含めることができますか。私はアイテムを定義し、特定のアイテムで発生するすべての事象をカプセル化したかったのです。
私はまた、クラスを見ているときに理由を説明するのが混乱する構文を発見した。修飾語が書かれた方法と要素が書かれた方法との間の差異は無視できる程度であった。これは簡単な修正ですが、まだそれについて私を盗んだものでした。
最後に、私は余分なものが必要であることを知った。私はモジュールのさまざまなコンテキストを伝達して容易にする能力が必要でした。「物」が同じロジックによって作成されていても、異なる状況で違ったスタイルやスタイルで使用できるようになったとき、私はそれを伝える手段が必要でした。
SMACSSから、私が有用であると主張したことは、状態を扱うことでした。私はis-pressedクラスや.btn[data-state=pressed]属性が要素の状態を明確に伝える方法が好きでした。
OOCSSは、私が必要としていたことの逆説であることが判明しました。私はOOCSSが提供できるものを評価していますが、私が持っていた問題の解決策ではありませんでした。私は作者がDOM /テンプレートでビジュアルを構築するために使用できるスタイルのレゴボックスを作成したくありませんでした。OOCSSの抽象化は、本質的に「漏れ易い」ものであり、メンテナンスに問題があった(あるルールの価値を変え、多くの要素に影響を及ぼす可能性がある)が、すでに説明した理由から、様々なビューポートを扱う方法を見つけることも困難でした。
最終的には、これらの既存のソリューションのそれぞれを試したり、失敗させたり、程度を変えることによって、私はついに私の問題を完全に理解しました。今すぐ注文されたソリューションを調整する時間でした。パブロ・ピカソの言い換え:
優れたコーダーがコピーして、偉大なコーダーがPablo Picassoを盗みます(Pabloの申し訳ありません)
私と一緒に歩いてください。
-- WIP --