CSS ネスト

CSS プリプロセッサの人気機能の 1 つであるスタイルルールのネスト機能が、言語に組み込まれました。

ネストする前は、すべてのセレクタを個別に明示的に宣言する必要がありました。これにより、繰り返し、スタイルシートの膨大化、分散したオーサリング エクスペリエンスが発生します。

変更前
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

ネストすると、セレクタを続行し、関連するスタイルルールをその中にグループ化できます。

変更後
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

ブラウザで試す

ネストを使用すると、セレクタを繰り返す必要が減り、関連する要素のスタイルルールを同じ場所に配置できるため、デベロッパーにとって便利です。また、スタイルをターゲットとする HTML と一致させることにも役立ちます。前の例の .nesting コンポーネントがプロジェクトから削除された場合は、関連するセレクタ インスタンスがファイルにないか検索する代わりに、グループ全体を削除できます。

ネストは、次の場合に役立ちます。 - 整理 - ファイルサイズの削減 - リファクタリング

ネスト機能は Chrome 112 で利用可能で、Safari Technical Preview 162 で試すこともできます。

CSS ネストのスタートガイド

この投稿の残りの部分では、次のデモ サンドボックスを使用して選択内容を可視化します。このデフォルト状態では、何も選択されておらず、すべてが表示されます。さまざまな形状とサイズを選択して、構文を練習し、動作を確認できます。

大小の円、三角形、四角形がカラフルに並んだグリッド。

サンドボックスの中には、円、三角形、四角形があります。小、中、大の 3 種類があります。その他の色は、青、ピンク、紫です。これらはすべて、.demo を含む要素内にあります。以下は、ターゲティングする HTML 要素のプレビューです。

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

ネストの例

CSS のネストを使用すると、別のセレクタのコンテキスト内で要素のスタイルを定義できます。

.parent {
  color: blue;

  .child {
    color: red;
  }
}

この例では、.child クラスセレクタ.parent クラスセレクタ内にネストされています。つまり、ネストされた .child セレクタは、.parent クラスを持つ要素の子要素にのみ適用されます。

この例は、& 記号を使用して、親クラスを配置する場所を明示的に指定することもできます。

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

これらの 2 つの例は機能的には同じです。この記事でより高度な例を検討するにつれて、オプションが必要な理由が明確になります。

サークルの選択

この最初の例では、デモ内の円だけをフェードしてぼかすスタイルを追加します。

ネストなしの現在の CSS:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

ネストする場合は、次の 2 つの方法が有効です。

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

または

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

結果: .circle クラスの .demo 内のすべての要素がぼやけて、ほとんど見えなくなります。

カラフルな図形のグリッドに円がなくなり、背景に非常に薄く表示されます。
Demo を試す

任意の三角形と正方形を選択する

このタスクでは、複数のネストされた要素(グループ セレクタ)を選択する必要があります。

ネストを行わない場合、CSS には次の 2 つの方法があります。

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

または、:is() を使用します。

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

ネストありの場合、次の 2 つの方法が有効です。

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

または

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

結果: .demo 内に残るのは .circle 要素のみです。

カラフルな図形のグリッドに残っているのは円のみで、他の図形はほとんど見えません。
デモを試す

大きな三角形と円を選択する

このタスクでは、複合セレクタが必要です。要素が選択されるには、両方のクラスが存在している必要があります。

ネストなしの現在の CSS:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

または

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

ネストありの場合、次の 2 つの方法が有効です。

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

または

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

結果: 大きな三角形と円がすべて .demo 内に隠されます。

カラフルなグリッドには、小さい形と中程度の形のみが表示されます。
Demo を試す
複合セレクタとネストに関する上級者向けのヒント

ネストされたセレクタを結合する方法が明示的に示されているため、ここでは & 記号が役に立ちます。たとえば次のようになります。

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

ネストの有効な方法ですが、結果は期待される要素と一致しません。これは、.lg.triangle, .lg.circle の組み合わせで望ましい結果を指定するための & がないと、実際の結果は .lg .triangle, .lg .circle(子孫セレクタ)になるためです。

ピンクの形状を除くすべての形状を選択

このタスクには、否定機能の疑似クラスが必要です。この場合、要素に指定されたセレクタが設定されていない必要があります。

ネストなしの CSS は次のようになります。

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

ネストありの場合、次の 2 つの方法が有効です。

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

または

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

結果: ピンク以外のすべてのシェイプが .demo 内に隠されます。

カラフルなグリッドがモノクロになり、ピンクの形状のみが表示されるようになりました。
Demo を試す
& による精度と柔軟性

:not() セレクタで .demo をターゲットに設定するとします。& は、次の場合に必須です。

.demo {
  &:not() {
    ...
  }
}

これは、.demo :not() を必要とした前述の例とは対照的に、.demo:not().demo:not() に結合します。この注意事項は、:hover インタラクションをネストする場合に非常に重要です。

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

ネストのその他の例

ネストの CSS 仕様には、その他の例が記載されています。構文について例で詳しく学びたい場合は、有効な例と無効な例の幅広い例をご覧ください。

次の例では、CSS のネスト機能について簡単に説明します。これにより、この機能の幅広い機能を理解できます。

@media のネスト

セレクタとそのスタイルを変更するメディアクエリ条件を見つけるために、スタイルシートの別の領域に移動するのは非常に煩わしい作業です。条件をコンテキスト内にネストできるため、この問題は解消されます。

ネストされたメディアクエリが現在のセレクタ コンテキストのスタイルのみを変更する場合は、構文を簡素化できます。

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

& を明示的に使用することもできます。

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

この例では、& で拡張された構文を示しています。また、.large カードをターゲットに設定して、追加のネスト機能が引き続き機能することを示しています。

詳しくは、@rules のネストをご覧ください。

どこでもネスト

ここまでの例はすべて、前のコンテキストを継続または追加しています。必要に応じて、コンテキストを完全に変更または並べ替えることができます。

.card {
  .featured & {
    /* .featured .card */
  }
}

& 記号はセレクタ オブジェクト(文字列ではない)への参照を表し、ネストされたセレクタ内の任意の場所に配置できます。複数回配置することもできます。

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

この例は少し無駄に見えますが、セレクタのコンテキストを繰り返すことができる場合もあります。

無効なネストの例

無効なネスト構文のシナリオがいくつかあり、プリプロセッサでネストしている場合は驚くかもしれません。

ネストと連結

多くの CSS クラスの命名規則では、ネストによってセレクタを文字列のように連結または追加できることを前提としています。セレクタは文字列ではなくオブジェクト参照であるため、CSS のネストでは機能しません。

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

詳細な説明については、仕様をご覧ください。

複雑なネストの例

セレクタリストと :is() 内のネスト

次のネストされた CSS ブロックについて考えてみましょう。

.one, #two {
  .three {
    /* some styles */
  }
}

これは、セレクタリストで始まり、ネストを続ける最初の例です。これまでの例では、セレクタリストで終わっていました。このネスト例には無効なものはありませんが、セレクタリスト内のネスト(特に ID セレクタを含むもの)には、実装の詳細で問題が生じる可能性があります。

ネストの意図が機能するように、最も内側のネストではないセレクタリストは、ブラウザによって :is() でラップされます。このラップにより、作成されたコンテキスト内でセレクタリストがグループ化されたままになります。このグループ化(:is(.one, #two))の副作用として、かっこ内のセレクタの中でスコアが最も高いセレクタの特定度が採用されます。これは :is() が常に機能する方法ですが、ネスト構文を使用すると、作成された内容と完全に一致しないため、驚くかもしれません。要約すると、ID とセレクタリストを使用してネストすると、非常に高い特定性のセレクタにつながる可能性があります。

複雑な例をわかりやすく説明するために、前のネスト ブロックをドキュメントに適用すると次のようになります。

:is(.one, #two) .three {
  /* some styles */
}

ID セレクタを使用しているセレクタリスト内にネストすると、そのセレクタリスト内のすべてのネストの特異性が高くなるため、注意してください。または、リンターに警告するように指示してください。

ネストと宣言の混在

次のネストされた CSS ブロックについて考えてみましょう。

.card {
  color: green;
  & { color: blue; }
  color: red;
}

.card 要素の色は blue になります。

混在するスタイル宣言は、ネストが発生する前に作成されたかのように、一番上にホイスティングされます。詳しくは、仕様をご覧ください。

回避する方法はいくつかあります。次のコードは、3 つのカラースタイルを & でラップします。これにより、作成者の意図したカスケード順序が維持されます。.card 要素の色は赤になります。

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

実際には、ネスト後に続くスタイルは & でラップすることをおすすめします。

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

特徴検出

CSS のネストを検出するには、ネストを使用するか、@supports を使用してネスト セレクタの解析機能をチェックする 2 つの方法があります。

Bramus の Codepen デモのスクリーンショット。ブラウザが CSS ネストをサポートしているかどうかを尋ねています。その質問の下に緑色のボックスが表示され、サポートされていることを示します。

ネストを使用する:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

使用中: @supports

@supports (selector(&)) {
  /* nesting parsing available */
}

私の同僚の Bramus が、この戦略を示す素晴らしい Codepen を作成しています。

Chrome DevTools を使用したデバッグ

ネストのサポートは、現在 DevTools で最小限に抑えられています。現在、スタイルは [スタイル] ペインに想定どおりに表示されますが、ネストとその完全なセレクタ コンテキストのトレースはまだサポートされていません。Google は、このプロセスを透明かつ明確にするための設計と計画を策定しています。

Chrome DevTools のネスト構文のスクリーンショット。

Chrome 113 では、CSS のネストをさらにサポートする予定です。最新情報を随時ご確認ください。

今後について

CSS のネストはバージョン 1 のみです。バージョン 2 では、より多くの構文糖衣が導入され、覚えておくべきルールが減る可能性があります。ネストの解析が制限されず、複雑にならないようにすることが求められています。

ネストは CSS 言語の大きな機能強化です。これは、CSS のアーキテクチャのほぼすべての側面に影響します。バージョン 2 を効果的に指定するには、この大きな影響を深く調査して理解する必要があります。

最後に、@scope、ネスト、@layer をすべて使用するデモを紹介します。とても楽しみです。

グレーの背景に明るいカード。カードには、タイトルとテキスト、いくつかのアクション ボタン、サイバーパンク スタイルの画像があります。