代表的な面接トピック

フロントエンド面接:コンポーネントの境界に CSS @scope をどのように活用しますか?

フロントエンド普通
Offer.cc 編集チーム公開日 更新日

質問

大規模なページ上のグローバル CSS が、カードや埋め込みコンポーネントに影響を与え続けています。CSS @scope を使ってセレクターを制限し、Shadow DOM や CSS Modules との境界を説明した上で、サポートのないブラウザで安全にフォールバックさせるにはどうすればよいですか?

1. 質問とコンテキスト

サーバーレンダリングされた管理ページに、汎用的な .title.button クラスを使用する複数のコンポーネントが存在します。新しいマーケティングカードによって、古いページ上のボタンの余白や見出しの色が変わってしまいます。サーバーレンダリングによる初回描画、テーマ変数、古いブラウザのサポートを維持しながら、@scope を使った段階的な移行を設計してください。コンポーネントは単一のドキュメント DOM 内に留まり、Shadow DOM は使用しません。

2. 面接官が評価するポイント

  • @scope がセレクターの一致範囲を制限するものであり、Shadow DOM のような分離を作成するわけではないことの理解。
  • 構文の丸暗記ではなく、スコーピングルート、オプションのスコープリミット、ネストされたスコープ、およびカスケード順序の説明。
  • コンポーネントの状態、テーマ変数、グローバルリセット、およびサードパーティ製スタイルの分離。
  • 機能検出、フォールバック動作、ビジュアルリグレッション、および移行メトリクスの設計。

3. 最初に明確にすべき質問

  1. どのブラウザを動作対象とする必要があり、非サポートブラウザはピクセル完全である必要があるか、それともレガシーな CSS パスを使用するか?
  2. コンポーネントは DOM を共有してテーマ変数を継承するのか、それとも真の DOM およびイベントの分離が必要か?
  3. スタイルはページごと、コンポーネントごと、サードパーティパッケージごとのいずれで読み込まれるか。また、古いルールと新しいルールはどのくらいの期間共存するか?
  4. スコープはルートのすべての子孫をカバーすべきか、それともネストされたサブツリーで停止すべきか?

4. 30秒での回答

私は @scope を Shadow DOM ではなく、セレクター範囲の制御として扱います。各コンポーネントに安定したルートクラスを与え、そのルールをスコープ内に保持します。ネストされた境界で一致を停止する必要がある場合は to を使用します。テーマ変数は明示的なページまたはコンポーネントのルートに保持し、状態はローカルなクラスまたは属性で表現します。サポートブラウザではスコープ化されたルールを使用し、非サポートブラウザでは同じセマンティックルールから生成された名前空間付きビルドを使用します。カスケードレイヤー、ビジュアルリグレッション、ルールヒットメトリクスを用いてコンポーネントを1つずつ移行し、新旧のセレクターが暗黙のうちに競合しないようにします。

5. ステップごとの回答

ステップ 1: 分離の目的を切り分ける

問題がセレクターの衝突なのか、継承の汚染なのか、それとも DOM/イベントのセキュリティ境界なのかを判断します。@scope は、同じドキュメントノードへの変数継承やスクリプトアクセスを許可したまま、セレクターの到達範囲に対処します。DOM、スタイル、イベントを分離する必要がある場合は Shadow DOM を選択し、ビルド時のモジュール化されたクラス名が主な目的である場合は CSS Modules を選択します。

ステップ 2: スコープルートとリミットを定義する

コンポーネントルートをスコープルートとして使用し、内部セレクターの可読性を保ちます:

css
@scope (.profile-card) {
  .title { color: var(--card-title); }
  .button { padding-inline: 0.75rem; }
}

.profile-card 内にネストされたサードパーティ製エディタを除外するには、@scope (.profile-card) to (.editor) { ... } を使用します。リミットは一致が停止する場所を示すだけであり、ノードを複製したり、カスタムプロパティの継承をブロックしたりするわけではありません。1つの要素が誤って複数のコンポーネントに所有されないよう、ネストされたスコープのルートとリミットを文書化します。

ステップ 3: カスケード、状態、テーマを処理する

スコープ化はカスケードを置き換えるものではありません。リセット、コンポーネントのデフォルト、オーバーライドを明示的な @layer に配置します。セレクターの詳細度を上げるのではなく、ルールをオーバーライドしやすく保ちたい場合は :where() を使用します。コンポーネントルート上で [data-state] やローカルクラスを使用して状態を表現し、それらのルールを定義されたレイヤーに割り当てます。テーマ変数はページルートから取得するか、コンポーネントルートでオーバーライドできますが、内部変数が誤ってグローバルな規約にならないようにする必要があります。

ステップ 4: 互換性と移行を設計する

@supports selector(:scope) またはブラウザターゲットマトリクスを使用してパスを選択し、実際のターゲットブラウザを検証します。レガシービルドでは、同じルールを .profile-card .title などの名前空間付きセレクターに展開できます。両方のパスは1つのソースルールセットから生成されなければなりません。コンポーネントごとに移行し、新旧のルールが共存している間にスクリーンショットを比較し、新しいパスが観測可能になった後にのみ古いグローバルセレクターを削除します。アプリケーション全体を1つの巨大なスコープでラップしないでください。

ステップ 5: 境界とロールバックを検証する

ネストされたコンポーネント内の同名クラス、スコープルート自体、to 境界の外側の要素、テーマの変更、組み合わせた状態、動的に挿入されたノード、サードパーティのサブツリーをテストします。ビルド出力におけるスコープ付きルールのカバレッジ、ブラウザ機能の分布、ビジュアル差分、一致しなかったルールを追跡します。リグレッションが増加した場合は、コンポーネントをロールバックするか拡張パスを無効化します。詳細度を追加して境界エラーを隠蔽してはなりません。

6. 模範解答

私はまず、セレクターの境界が必要なのか、完全な DOM 分離が必要なのかを判断します。共有ドキュメント DOM の場合、@scope (.profile-card) は内部セレクターをローカルに保ち、to はネストされたエディタで一致を停止できます。これは Shadow DOM のようにイベントを分離したり、カスタムプロパティの継承を防いだりするものではありません。リセット、デフォルト、状態のオーバーライドを明示的なカスケードレイヤーに配置し、テーマ変数はページまたはコンポーネントのルートでのみ定義します。非サポートブラウザには、同じルールから生成された名前空間付きビルドを使用します。移行は、スクリーンショットの差分、機能分布、一致しないルールのメトリクスを用いてコンポーネントごとに進めます。境界のリグレッションが発生した場合は、セレクターの詳細度を引き上げるのではなく、そのコンポーネントをロールバックします。

7. よくある間違い

  • @scope を Shadow DOM として扱うこと: DOM、イベント、変数は共有されたままです。分離の目的に合ったプリミティブを選択してください。
  • セレクターを変更しながらレイヤーを無視すること: 古いルールが上位のレイヤーで勝ってしまう可能性があります。レイヤーと状態の優先順位を一緒に定義してください。
  • アプリケーション全体を1つのスコープでラップすること: コンポーネント境界の恩恵が薄れ、ロールバックが困難になります。コンポーネントルートごとに分割してください。
  • 古いブラウザでルールが無視されるのを放置すること: 重要なスタイルが失われます。名前空間付きのレガシーパスを提供し、機能マトリクスをテストしてください。
  • より高い詳細度でリグレッションを修正すること: 結合度とオーバーライドコストが増加します。ルート、スコープリミット、カスケードレイヤーを再設計してください。

8. フォローアップ質問と回答

フォローアップ 1: @scope は子コンポーネントがテーマ変数を継承するのを防ぐことができますか?

いいえ。これは主にセレクターの一致を制限するものであり、カスタムプロパティは依然として CSS の継承に従います。子コンポーネントのルートで変数をオーバーライドするか、独立した変数環境が必要な場合は Shadow DOM を使用してください。

フォローアップ 2: ネストされたスコープが同じ要素に一致した場合、どちらが優先されますか?

通常通りのカスケードおよびスコープ関連の順序が適用されます。「常に内側のスコープが勝つ」というわけではありません。スコープを定義されたレイヤーに配置し、ブラウザの DevTools で最小限の再現環境を確認してください。

フォローアップ 3: 非サポートブラウザで一貫性を保つにはどうすればよいですか?

同じソースルールから名前空間付きセレクターまたは安定した CSS Modules クラスを生成し、変数、状態、レイヤーのセマンティクスを維持します。ランタイム検出によって実装パスを選択し、ビジネスコンポーネントが2つのステートマシンを維持しないようにします。

公開情報ソース

関連する質問