15 年近くの経験を持つフロントエンド開発者として、私は Web 開発の進化を直接目撃してきました。私にとって、変更されたファイルを FTP 経由でアップロードしていた時代 (はい、GitHub は 15 年前に開始されましたが、私がそれを知ったのは 2011 年でした) から、応答性の高いインターフェイス、UI ライブラリ、Web サイトから直接生成された現代の時代まで、長い道のりを歩んできました。フィグマ。 それでも、次のような入れ子スタイルを採用するプロジェクトに今でも遭遇します。 .some-class ul li div a { /* some style */ } また、 #nav .nav-link svg { /* some style */ } 衝撃的に思えるかもしれませんが、このようなコーディングの実践は、数百万ドル規模の急速に成長するプロジェクトから小規模なスタートアップ企業に至るまで、あらゆるものに浸透しています。 このアプローチが問題を引き起こす可能性がある理由を詳しく見てみましょう。 入れ子になったスタイルの衝突 深くネストされたスタイルは、特に大規模なプロジェクトの場合、スタイルの競合を引き起こすことがよくあります。 CSS はカスケード スタイル シートとして、要素の特異性に応じて要素にカスケードして適用されます。深く入れ子になったスタイルは、その特殊性により、意図せずに他のスタイルをオーバーライドする可能性があります。 次の例を考えてみましょう。 .some-class ul li div a { color: red; } ... .some-class a { color: blue; } 内のすべてのリンクが青色になることが予想されるかもしれません。ただし、最初のルールの方が特異性が高いため、 内にネストされたリンクは青ではなく赤になります。これにより、予期しない視覚的な不一致が発生し、デバッグに多くの時間が無駄になる可能性があります。 .some-class ul > li > div 特異性の複雑さ CSS の特異性 (またはスタイルの「重み」) の概念を理解することは、深いネストがなぜ問題になるかを理解するために重要です。単一の要素に対して複数のルールが競合する場合、特異性によってどの CSS ルールが適用されるかが決まります。セレクターの種類と数に基づいて計算されます。 特異性は、4 つのカテゴリの重み付けシステムに基づいて計算されます。 インラインスタイル ID クラス、属性、および疑似クラス 要素と擬似要素 ここで、次のルールを考えてみましょう。 body #content .data img:hover { /* some style */ } 特異度は です。それは 1 つの ID ( )、2 つのクラス ( と )、および 2 つの要素 ( と ) です。 0 1 2 2 #content .data :hover body img ここで、次のルールを考えてみましょう。 #nav .nav-link svg { /* some style */ } ここでの特異度は です。それは 1 つの ID ( )、1 つのクラス ( )、および 1 つの要素 ( ) です。 0 1 1 1 #nav .nav-link svg 特異性は、従来の 10 進数のような「繰り越し」システムでは機能しません。たとえば、10 進法では と は等価ですが、特異性 のセレクターは、特異性 0 1 1 1 と等しくありません。 11 1+1 0 1 0 11 最後に、ユニバーサル セレクター ( )、コンビネーター ( 、 、 、 ' ')、および否定擬似クラス ( ) は、特異性には影響しません。ただし、 引数内では、セレクターは通常どおりカウントされます。 * + > ~ :not() :not() 視覚的な学習者には、CSS の特異性に関する をお勧めします。 このビデオ CSS の特異性とその計算方法を理解すると、より適切で予測可能な CSS を記述し、スタイルが期待どおりに適用されない場合の問題をデバッグできるようになります。 ルールと具体性 !important 開発者は、CSS の特異性の競合による問題に直面した場合、 ルールの使用に頼ることがあります。このルールにより、CSS プロパティが非常に限定的になります。つまり、他のほとんどすべての宣言がオーバーライドされます。 !important 例えば: #nav .nav-link svg { color: blue; } .nav-link svg { color: red !important; } 最初のルールは ID セレクターにより高い特異性を持っていますが、2 番目のルールの により の色は赤になります。 !important svg ! important を使いすぎることのリスク 特異性の問題に直面した場合の迅速な解決策にはなりますが、広範囲に使用することはお勧めできません。過度に使用すると、保守性、予測可能性、パフォーマンスに影響を与える可能性があります。大規模なプロジェクトでは、 の過剰使用は、CSS の特異性の管理に苦労していることを示していることがよくあります。多くの場合、 に頼るよりも、CSS をリファクタリングし、過度に特殊なセレクターの使用を減らすことに時間を投資する方が良いでしょう。 !important !important !important 今すぐ製品をチェックできます 🙂。私は自分のものを確認しました: 簡単な修正としては魅力的かもしれません。それはナッツを割るために大ハンマーを使うようなものです。より保守しやすいアプローチは、セレクターをできるだけシンプルかつフラットに保つことです。これにより、将来の CSS の理解、管理、拡張が容易になります。そして覚えておいてください、 戦争に勝つための最善の方法は、最初から戦争を始めないことです。 !important !important CSS ツリーのトラバース 深くネストされたスタイルに関するもう 1 つの問題は、ブラウザーのレンダリングに対するパフォーマンスへの影響です。ブラウザーが要素にスタイルを適用すると、キー セレクター (この例では と ) から始まり、一致するものが見つかるか先頭に到達するまで、祖先を通って DOM を右から左に移動します。スタイルのネストが増えるほど、この走査にかかる時間が長くなり、パフォーマンスに影響を与え、大規模プロジェクトのページ読み込み時間が遅くなる可能性があります。 a svg 次のように CSS ルールを指定する場合: .some-class ul li a { /* some style */ } このルールは、ツリーの一番下 ( タグから) から始まり、ツリー全体に ( 、 、および を介して) 進んでいく様子を視覚化できます。 a li ul .some-class ブラウザは最初に (つまりすべて) の 要素を検索し、次にこれらの タグが 要素内にあるかどうかを確認します。その後、これらの 要素が 内にあるかどうかをチェックします。そして最後に、これらの クラスの要素内にあるかどうかをチェックします。 すべて a a li li ul ul .some-class これが、ブラウザーが CSS セレクターを読み取る方法と、複雑なセレクターがページのレンダリングの低下につながる理由です。ブラウザは、要素ごとに複数のチェックを行って、指定されたルールに適合するかどうかを確認する必要があります。ルールが深くなるほど、ブラウザが実行する必要があるチェックが増え、パフォーマンスに影響を与える可能性があります。 大規模プロジェクトで CSS を管理するためのより良いプラクティス CSSモジュール 、作業しているコンポーネントをローカルにスコープする個々のモジュールに CSS を記述することができます。つまり、CSS モジュールのスタイルはその特定のモジュールにのみ適用され、ページ上の他の要素に漏れたり影響を与えたりすることはありません。 CSS モジュールを使用すると CSS モジュールがハッシュ化されたクラス名を使用してスタイルのカプセル化を保証する方法を見てみましょう。 CSS モジュールを使用している場合、CSS ファイルで定義したクラス名はコンパイル時にハッシュされます。このハッシュにより、コンポーネントに対応する一意のクラス名が作成されます。例を見てみましょう: CSS モジュールが次のように定義されているとします。 /* Button.module.css */ .button { color: white; background-color: blue; } そして、これをコンポーネント内で次のように使用します (私は、 代わりにスタイル オブジェクトを としてインポートすることを好みます。これは、入力時間を節約し、コーディング効率を高めるための簡単なヒントです)。 styles s import React from 'react'; import s from './Button.module.css'; const Button = () => { return ( <button className={s.button}>Click me</button> ); }; export default Button; アプリケーションがコンパイルされると、レンダリングされた HTML は次のようになります。 <button class="Button_button__3FQ9Z">Click me</button> この場合、 、CSS モジュールから生成されたハッシュされたクラス名です。ハッシュの正確な構造と長さは、プロジェクトの構成によって異なる場合があることに注意してください。 Button_button__3FQ9Z この一意のクラス名により、 で定義したスタイルがこのボタンにのみ適用され、アプリケーション内の他の要素には影響しません。また、ハッシュされたクラス名を明示的にターゲットにしない限り、他のスタイルがこのボタンに影響を与えることはできません。このスタイルのカプセル化は、CSS モジュールの主な利点の 1 つです。 Button.module.css CSS-in-JS ライブラリ CSS を処理するもう 1 つの一般的な方法は、 や などの CSS-in-JS ライブラリを使用することです。これらのライブラリを使用すると、JavaScript 内に CSS を直接記述することができ、これにはいくつかの利点があります。 styled-components 情動 : CSS モジュールと同様に、スタイルのスコープは、スタイルが定義されているコンポーネントに限定されます。 スコープ付きスタイル : コンポーネント内のプロパティや状態に基づいて動的スタイルを簡単に作成できます。 動的スタイル : スタイル内で JavaScript ロジックを直接使用でき、コンポーネントに関連するすべてが 1 か所に配置されるため、コードが理解しやすく、操作しやすくなります。 開発者エクスペリエンスの向上 React アプリケーションでスタイル付きコンポーネントを使用する方法の例を次に示します。 import React from 'react'; import styled from 'styled-components'; const Button = styled.button` color: white; background-color: ${(props) => props.primary ? 'blue' : 'gray'}; `; const App = () => { return ( <div> <Button primary>Primary Button</Button> <Button>Secondary Button</Button> </div> ); }; export default App; この例では、 コンポーネントには、 プロパティに基づいて変化する動的スタイルがあります。 Button primary BEM 手法 CSS モジュールなどをサポートする JavaScript フレームワークを使用していない場合でも、 BEM (ブロック、要素、モディファイア) などの命名方法を使用して CSS を効果的に管理できます。 BEM は「Block Element Modifier」の略で、CSS で再利用可能なコンポーネントとコード共有を作成するのに役立つ方法論です。BEM を使用して CSS を構造化する方法は次のとおりです。 /* Block */ .top-menu { } /* Element */ .top-menu__item { } /* Modifier */ .top-menu__item_active { } BEM では、「ブロック」はそれ自体で意味のあるスタンドアロンのエンティティであり、「要素」はスタンドアロンの意味を持たず、意味的にそのブロックに関連付けられているブロックの一部であり、「修飾子」はフラグです。外観や動作を変更するために使用されるブロックまたは要素。 BEM のような一貫した方法論を使用すると、特に大規模なプロジェクトにおいて、CSS の理解と保守が容易になります。 結論は CSS モジュールや CSS-in-JS ライブラリから BEM のような命名方法まで、大規模なプロジェクトで CSS を管理する方法はいくつかあります。重要なのは、チームやプロジェクトに適したアプローチを見つけて、それを一貫して適用することです。 CSS を書くということは、理解しやすく保守しやすいコードを書くことであるのと同じくらい、効率的でパフォーマンスの高いコードを書くことでもあるということを忘れないでください。 コーディングを楽しんでください!