基本的な CSS の原則を学ぶときは、保守性を確保するために、モジュール式で再利用可能な説明的なスタイルを作成することを学びます。しかし、開発者が実際のアプリケーションに関わるようになると、意図しない領域にスタイルが漏れることなく UI 機能を追加するのは不可能だと感じることがよくあります。 この問題は雪だるま式に自己実現ループに陥ることがよくあります。理論的には 1 つの要素またはクラスにスコープされているスタイルが、属していない場所に表示され始めます。これにより、開発者はリークされたスタイルをオーバーライドするためにさらに具体的なセレクターを作成する必要があり、そのセレクターが誤ってグローバル スタイルをオーバーライドしてしまうなどの事態が発生します。 BEM などの厳格なクラス名規則は、この問題に対する理論的な解決策の 1 つです。 BEM (ブロック、エレメント、モディファイア) 手法は、CSS ファイル内の再利用性と構造を確保するために CSS クラスに名前を付ける体系的な方法です。このような命名規則は、ドメイン言語を利用して要素とその状態を説明することで認知負荷を軽減でき、正しく実装されていれば、大規模なアプリケーションのスタイルを維持しやすくなります。 しかし、現実の世界では、必ずしもそのようにうまくいくとは限りません。優先順位は変更される可能性があり、変更すると実装に一貫性がなくなります。 HTML 構造に小さな変更を加えると、多くの CSS クラス名の改訂が必要になる場合があります。高度にインタラクティブなフロントエンド アプリケーションでは、BEM パターンに従ったクラス名が長くて扱いにくくなる可能性があり (例: app-user-overview__status--is-authenticating)、命名規則に完全に準拠していないとシステムの構造が壊れ、その利点が損なわれます。 これらの課題を考慮すると、開発者がフレームワークに目を向けたのも不思議ではありません。Tailwind が最も人気のある CSS フレームワークです。スタイル間の勝ち目のない特殊性戦争のように戦おうとするよりも、CSS カスケードを諦めて、完全な分離を保証するツールを使用する方が簡単です。 開発者はユーティリティについてさらに学ぶ 一部の開発者がカスケード スタイルを避けることに熱心であることをどのようにして知ることができるでしょうか?それは、その目的のために特別に設計された、CSS-in-JS フレームワークのような「最新の」フロントエンド ツールの台頭です。特定のコンポーネントに厳密に限定された独立したスタイルで作業することは、新鮮な空気の息吹のように思えるかもしれません。これにより、依然として最も嫌われており、時間のかかるフロントエンド タスクの 1 つである名前を付ける必要がなくなり、開発者は CSS 継承の利点を完全に理解したり活用したりしなくても、生産性を高めることができます。 しかし、CSS Cascade を廃止すると、それ自体に問題が生じます。たとえば、JavaScript でスタイルを作成するには多大なビルド構成が必要であり、スタイルがコンポーネントのマークアップや HTML とぎこちなく混在することがよくあります。慎重に考慮された命名規則の代わりに、ビルド ツールがセレクターと識別子 (.jsx-3130221066 など) を自動生成できるようにするため、開発者はそれ自体でさらに別の疑似言語に対応する必要があります。 (コンポーネントの useEffects が何を行うのかを理解するという認知的負荷だけではまだ十分ではないかのように!) クラスに名前を付けるジョブをツールにさらに抽象化すると、基本的なデバッグは、開発者ツールなどのライブ デバッグをサポートするネイティブ ブラウザ機能を活用するのではなく、開発用にコンパイルされた特定のアプリケーション バージョンに制限されることがよくあります。 それはまるで、Web がすでに提供しているものを抽象化するために使用しているツールをデバッグするためのツールを開発する必要があるかのようです。すべては、標準 CSS を記述する「苦痛」から逃げるためです。 幸いなことに、最新の CSS 機能により、標準 CSS の記述がより柔軟になるだけでなく、私たちのような開発者にカスケードを管理して機能させるための大幅な権限も与えられます。 CSS カスケード レイヤーはその良い例ですが、驚くほど注目されていない機能がもう 1 つあります。ただし、最近 Baseline 互換になったため、その点は変わりつつあります。 CSS @scope At-Rule 私は、CSS @scope at-rule が、これまで取り上げてきたようなスタイル漏洩によって引き起こされる不安に対する潜在的な治療法であると考えています。これにより、抽象化や追加のビルド ツールによってネイティブ Web の利点を犠牲にする必要がなくなります。 「@scope CSS at-rule を使用すると、特定の DOM サブツリー内の要素を選択できるようになり、オーバーライドが難しい過度に特定的なセレクターを作成したり、セレクターを DOM 構造に緊密に結合したりすることなく、要素を正確にターゲットにすることができます。」- MDN
言い換えれば、継承、カスケード、さらには関心事の基本的な分離を犠牲にすることなく、特定のインスタンスで分離されたスタイルを扱うことができます。これは、フロントエンド開発の長年にわたる指針となっています。 さらに、ブラウザーのカバー範囲も優れています。実際、Firefox 146 は 12 月に @scope のサポートを追加し、初めて Baseline 互換になりました。以下は、BEM パターンを使用したボタンと @scope ルールを使用したボタンの簡単な比較です。
<スタイル> .button .button__text { /* ボタンのテキストのスタイル */ } .button .button__icon { /* ボタンアイコンのスタイル */ } .button--primary { プライマリ ボタンのスタイル */ } スタイル>
<スタイル> @scope (.primary-button) { span:first-child { /* ボタンのテキスト スタイル */ } span:last-child { /* ボタンアイコンのスタイル */ } } スタイル>
@scope ルールを使用すると、複雑さを軽減しながら精度を高めることができます。開発者はクラス名を使用して境界を作成する必要がなくなり、ネイティブ HTML 要素に基づいてセレクターを作成できるようになり、規範的な CSS クラス名パターンが不要になります。 @scope はクラス名管理の必要性を取り除くだけで、大規模プロジェクトにおける CSS に伴う不安を軽減できます。
基本的な使い方
まず、@scope ルールを CSS に追加し、スタイルのスコープが設定されるルート セレクターを挿入します。
@scope (<セレクター>) {
/*
たとえば、スタイルの範囲を
@scope (ナビ) { a { /* nav スコープ内のスタイルをリンク */ }
a:active { /* アクティブなリンク スタイル */ }
a:active::before { /* 追加のスタイル用の疑似要素を含むアクティブなリンク */ }
@media (最大幅: 768px) { a { /* レスポンシブな調整 */ } } }
これ自体は画期的な機能ではありません。ただし、2 番目の引数をスコープに追加して下限を作成し、スコープの開始点と終了点を効果的に定義できます。
/* ul 内の要素にはスタイルが適用されません */ @scope (nav) to (ul) { { フォントサイズ: 14px; } }
この手法はドーナツ スコーピングと呼ばれ、DOM 構造に緊密に結合された一連の類似した非常に特殊なセレクター、:not 擬似セレクター、または異なる CSS を処理するために
/*
結論 Tailwind などのユーティリティ優先の CSS フレームワークは、プロトタイピングや小規模なプロジェクトに適しています。ただし、複数の開発者が関与する大規模なプロジェクトで使用すると、その利点はすぐに減少します。 フロントエンド開発はここ数年でますます複雑になり、CSS も例外ではありません。 @scope ルールは万能薬ではありませんが、複雑なツールの必要性を軽減できます。 @scope を戦略的なクラス命名の代わりに、またはそれと並行して使用すると、保守可能な CSS をより簡単に楽しく作成できるようになります。 さらに読む
CSS @scope (MDN) 「CSS @scope」、Juan Diego Rodríguez (CSS-Tricks) Firefox 146 リリースノート (Firefox) ブラウザのサポート (CanIUse) 人気の CSS フレームワーク (CSS 2024 の現状) 「CSS の「C」: カスケード」、トーマス・イップ (CSS-Tricks) BEM の概要 (BEM を入手する)