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 ネストを使ってみる

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

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

サンドボックス内には、円、三角形、正方形があります。小、中、大のサイズがあります。青、ピンク、紫の色があります。これらはすべて .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);
  }
}

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

カラフルな図形のグリッドに円がなくなりました。背景に非常に薄く表示されています。
[デモを試す]

三角形と正方形を選択する

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

ネストなし の場合、現在の 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);
  }
}

結果 : .circle 要素のみが .demo 内に残ります。

カラフルな図形のグリッドから円だけが残り、他の図形はほとんど見えなくなっています。
[デモを試す]

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

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

ネストなし の場合、現在の 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 {
  .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 内に隠されます。

カラフルなグリッドがモノクロになり、ピンクの図形のみが表示されています。
[デモを試す]
& による精度と柔軟性

: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 つの方法があります。

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

ネストを使用する場合:

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

  .no-nesting {
    display: none;
  }
}

@supports を使用する場合:

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

同僚の Bramus が、この戦略を示す 優れた Codepen を作成しました。

Chrome DevTools でのデバッグ

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

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

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

今後について

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

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

最後に、すべて一緒に使用するデモ を紹介します。@scope@layerどれも興味深いものです。

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