CSSネストとは、あるスタイルルールの波かっこの中に、別のルールを入れ子で書ける CSS の標準機能です。 Sass などのコンパイルなしで、ブラウザがそのまま読み取ります。.card { .title { ... } } と書けば .card .title に、.card { &:hover { ... } } と書けば .card:hover に当たります。

書き方は Sass とよく似ていますが、同じコードでも結果が変わる箇所が3つあります。&__elem のような文字列の連結ができないこと、詳細度が :is() と同じ計算になること、そしてネストの後ろに書いた宣言の順序です。この記事では、それぞれを Chromium 141 で実際に読み込ませ、適用された色や CSSOM(ブラウザが解釈したルールの構造)を出力して確かめました。対応ブラウザのバージョン表、Sass の BEM 記法からの書き換え表、コピペ用のパターン集も載せています。

CSSネストの早見表

書き方と展開結果

ネストの中の書き方(親は .card) 展開結果(同じ意味の書き方) & の扱い
.title { } .card .title 省略できる
& .title { } .card .title 書いても同じ
a { } .card a 省略できる(要素名で始めてもよい)
> li { } .card > li 省略できる
+ p { } .card + p 省略できる
&.active { } .card.active 必要
&:hover { } .card:hover 必要
&::before { } .card::before 必要
&:not(.on) { } .card:not(.on) 必要
.dark & { } .dark .card 必要(親を後ろに置く)
& + & { } .card + .card 必要
&__title { } (無効。読み飛ばされる) 書けない
&-wide { } (無効。読み飛ばされる) 書けない

対応ブラウザ(要点)

ブラウザ & が必須だった時期 要素名で始められる版(緩和後)
Chrome / Edge 112〜119 120 以降
Firefox (なし) 117 以降
Safari(macOS / iOS) 16.5〜17.1 17.2 以降

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CSSネストの書き方|&の使い方とSassとの違い・対応ブラウザ」

検証した環境

項目 版
ブラウザ Chromium 141.0.7390.37(Playwright 1.56.0 から起動)
Sass Dart Sass 1.105.1(npm の sass パッケージ)
対応ブラウザの版 npm の @mdn/browser-compat-data 8.1.4(2026-10-01 付)から取得

適用結果は getComputedStyle() で取り出した値、ルールの構造は document.styleSheets の cssRules をたどって出力したものです。Firefox と Safari での実行は行っていません(未実行)。この2つのブラウザについては、対応する版を上記のデータで確認しています。

基本の書き方

ネストなしの CSS と、ネストした CSS を並べます。

/* ネストなし */
.card { padding: 16px; }
.card .title { font-weight: 700; }
.card:hover { box-shadow: 0 4px 12px rgb(0 0 0 / 0.12); }

/* ネストあり(同じ意味) */
.card {
  padding: 16px;

  .title { font-weight: 700; }
  &:hover { box-shadow: 0 4px 12px rgb(0 0 0 / 0.12); }
}

親のセレクタを何度も書かずに済み、関連するルールがひとかたまりになるのが利点です。& は「親のセレクタそのもの」を表す記号で、ネストセレクタと呼ばれます。

&が必要なケース・省略できるケース

判断の基準は1つです。親との間に「空白(子孫)」やコンビネータ(>、+、~)が入るなら省略でき、親にぴったりくっつけたいなら & が必要です。

検証コード

次の HTML と CSS を読み込み、各要素の color を取り出しました。色の値(rgb(1,1,1) など)は、どのルールが当たったかを見分けるための目印です。

<div class="card">A
  <p class="title">B</p>
  <a>C</a>
  <span class="active">D</span>
</div>
<p>E</p>
<div class="card active">F</div>
<div class="dark"><div class="card">G</div></div>
<p class="title">H</p>
.card {
  color: rgb(1,1,1);
  .title { color: rgb(2,2,2); }
  a { color: rgb(3,3,3); }
  .active { color: rgb(40,40,40); }
  &.active { color: rgb(4,4,4); }
  + p { color: rgb(5,5,5); }
  .dark & { color: rgb(6,6,6); }
}

実行結果です。

A div.card => rgb(1, 1, 1)
B .card の中の p.title => rgb(2, 2, 2)
C .card の中の a => rgb(3, 3, 3)
D .card の中の span.active => rgb(40, 40, 40)
E .card の直後の p => rgb(5, 5, 5)
F div.card.active => rgb(4, 4, 4)
G .dark の中の div.card => rgb(6, 6, 6)
H .card の外の p.title => rgb(0, 0, 0)

D と F を見比べてください。.active { } は「.card の中にある .active」(D)に、&.active { } は「.card かつ .active」(F)に当たりました。 & の有無で対象がまったく別の要素になります。

ブラウザは & を自動で補っている

同じ形の CSS を読み込ませて、ブラウザが解釈したルールを出力すると次のようになります。

CSSStyleRule | .card | color: red;
  CSSStyleRule | & .title | color: blue;
  CSSStyleRule | &.active | color: green;
  CSSStyleRule | & + p | color: gray;
  CSSStyleRule | .dark & | color: navy;

.title と書いたルールは & .title に、+ p と書いたルールは & + p になっています。& を書かなかった場合、ブラウザが先頭に「& と空白」を補うということです。すでにどこかに & が書かれている .dark & には、何も補われていません。

書き方 ブラウザの解釈 意味
.title { } & .title 親の子孫の .title
+ p { } & + p 親の直後の p
&.active { } &.active 親かつ .active
:hover { } & :hover 親の子孫でホバー中の要素(親自身ではない)
.dark & { } .dark & .dark の中にある親

4行目がつまずきやすい箇所です(.card { :hover { ... } } を読み込ませると、解釈結果は & :hover でした)。:hover { } と & なしで書くと「親の中にある、ホバー中のすべての要素」になります。疑似クラス・疑似要素・属性セレクタ・クラスの重ねがけは、必ず & をくっつけて書くと覚えておくと迷いません。

入れ子を重ねたとき・セレクタリストのとき

.list {
  li {
    color: rgb(1,1,1);
    &.on { color: rgb(2,2,2); }
    &:not(.on) { font-weight: 700; }
    &::before { content: "- "; }
  }
}
h2, h3 { &.h { color: rgb(5,5,5); } }
.h { h2& { font-style: italic; } }
li => rgb(1, 1, 1)
li.on => rgb(2, 2, 2)
li font-weight: 700
li::before content: "- "
h2.h => rgb(5, 5, 5)
h3.h => rgb(5, 5, 5)
h2 font-style: italic / h3: normal

2段目の & は、1つ外側のルール全体(.list li)を指します。親が h2, h3 のようなセレクタリストなら、&.h は h2.h と h3.h の両方に当たります。最後の h2& は「h2 要素かつ .h」という意味で、h2 だけが斜体になりました。要素名と組み合わせるときは、要素名を先に、& を後ろに書きます。

書けないケース:&__elemの連結

Sass では &__elem と書くと、親のクラス名に文字列をつなげて .block__elem を作れます。CSSネストの & は文字列ではなく「親セレクタに当たる要素」を表すので、連結はできません。

.block {
  color: rgb(1,1,1);
  &__elem { color: rgb(9,9,9); }
}
<div class="block">
  <div class="block__elem">elem</div>
</div>
CSSStyleRule | .block | color: rgb(1, 1, 1);
block: rgb(1, 1, 1)
block__elem: rgb(1, 1, 1)

解釈されたルールは .block の1つだけで、&__elem のルールは丸ごと読み飛ばされました。.block__elem の文字色は、親から継承した rgb(1, 1, 1) のままです。エラーは表示されず、ほかのルールはそのまま有効なので、気づきにくい点に注意します。

同じ形のものをまとめて試した結果です。

書き方 Chromium 141 での結果
&__elem { } 読み飛ばされる
&-wide { } 読み飛ばされる
&_x { } 読み飛ばされる
&1 { } 読み飛ばされる
&div { } 読み飛ばされる
div& { } 有効(div 要素かつ親)
.block__elem { } 有効(& .block__elem と解釈)

無効なルールが1つあっても、同じ親の中のほかのルールには影響しません。.list { & %bad { ... } & .ok { ... } } と書いて確かめたところ、& .ok のルールは残っていました。

同じコードを Sass でコンパイルすると

.block {
  color: black;
  &__elem { color: gray; }
  &--wide { width: 100%; }
}
/* Dart Sass 1.105.1 の出力 */
.block {
  color: black;
}
.block__elem {
  color: gray;
}
.block--wide {
  width: 100%;
}

Sass はコンパイルの時点で文字列をつなげ、平らな CSS を出力します。Sass から拡張子だけ変えて移すと、BEM の &__ と &-- の部分がすべて効かなくなるので、次の表のように書き換えます。

SassのBEM記法からの書き換え対応表

Sass での書き方 CSSネストでの書き方 当たる対象
&__title { } .card__title { } .card の中の .card__title
&--wide { } &.card--wide { } .card かつ .card--wide
&__title--sub { } .card__title--sub { } .card の中の .card__title--sub
&:hover { } &:hover { } そのまま使える
&.is-open { } &.is-open { } そのまま使える
.dark & { } .dark & { } そのまま使える
& + & { } & + & { } そのまま使える
& > li { } > li { } または & > li { } そのまま使える
#{&}__title { } .card__title { } 補間は使えないのでクラス名を書く
@at-root .x { } ネストの外に書く ネストから抜ける指定はない

書き換え後のコードを実際に読み込ませました。

.card {
  color: rgb(1,1,1);
  .card__title { color: rgb(2,2,2); }
  &.card--wide { color: rgb(3,3,3); }
  .card__title--sub { color: rgb(4,4,4); }
}
card--wide => rgb(3, 3, 3)
card__title => rgb(2, 2, 2)
card__title--sub => rgb(4, 4, 4)

3つとも意図どおりに当たっています。なお、Sass の &__title は .card__title 単体(詳細度 0,1,0)になりますが、書き換え後の .card .card__title は詳細度が 0,2,0 に上がります。詳細度を上げたくないときは、エレメントのルールをネストの外に平らに書くのも良い選択です。

詳細度は:is()相当になる

2つ目の違いは詳細度です。& の詳細度は、親のセレクタリストの中で最も高いものが採用されます。 これは :is() と同じ計算方法です。

Sassと同じコードで結果が変わる例

#main, .card {
  .title { color: rgb(255,0,0); }   /* 赤 */
}
.card .title { color: rgb(0,0,255); }  /* 青 */
<div class="card">
  <p class="title">タイトル</p>
</div>

HTML に #main は登場しません。直感的には、後から書いた青が勝ちそうに見えます。結果は次のとおりです。

書き方 .card の中の .title の色 理由
CSSネスト(上のコード) rgb(255, 0, 0)(赤) :is(#main, .card) .title と同じで詳細度 1,1,0
Sass でコンパイルした CSS rgb(0, 0, 255)(青) #main .title, .card .title に展開され、.card 側は 0,2,0
:is(#main, .card) .title と書いた CSS rgb(255, 0, 0)(赤) CSSネストと同じ結果

Sass の出力は次のとおりで、セレクタが1つずつ展開されています。

/* Dart Sass 1.105.1 の出力 */
#main .title, .card .title {
  color: red;
}

.card .title {
  color: blue;
}

Sass では「当たったセレクタ(.card .title)」の詳細度 0,2,0 どうしの比較になり、後に書いた青が勝ちます。CSSネストでは、実際には当たっていない #main の詳細度まで含めて計算されるため、1,1,0 の赤が勝ちます。

詳細度を上げたくないときは:where()

親を :where() で包むと、その部分の詳細度が 0 になります。

:where(#main, .card) {
  .title { color: rgb(255,0,0); }
}
.card .title { color: rgb(0,0,255); }
title => rgb(0, 0, 255)

青が勝つようになりました。親のセレクタリストに ID と クラスを混ぜない、混ぜる必要があるときは :where() で包む、という2点で、Sass から移したときの差を小さくできます。

ネストの後ろに書いた宣言の扱い

3つ目の違いは、入れ子のルールより後ろに書いた宣言です。

.box {
  color: rgb(255,0,0);          /* 赤 */
  & { color: rgb(0,0,255); }    /* 青 */
  color: rgb(0,128,0);          /* 緑:ネストの後ろ */
}

& { } は親と同じ要素・同じ詳細度のルールです。Chromium 141 での結果は次のとおりです。

CSSStyleRule | .box | color: rgb(255, 0, 0);
  CSSStyleRule | & | color: rgb(0, 0, 255);
  CSSNestedDeclarations |  | color: rgb(0, 128, 0);
computed: rgb(0, 128, 0)

最後に書いた緑が適用されました。 ネストの後ろの宣言は CSSNestedDeclarations という独立したかたまりとして、書いた位置のまま扱われています。書いた順番どおりに後勝ちになるので、見た目と結果が一致します。

CSSNestedDeclarations に対応する前の版では、後ろに書いた宣言も先頭の宣言とまとめて扱われ、上の例は青になるとされています(以前の版での実行は今回行っていません。未実行)。対応した版は次のとおりです。

ブラウザ 書いた順のまま扱う版(CSSNestedDeclarations 対応)
Chrome / Edge 130 以降
Firefox 132 以降
Safari(macOS / iOS) 18.2 以降

@media を挟んだ場合も同じ動きです。

.box {
  color: rgb(255,0,0);
  @media (min-width: 1px) { color: rgb(0,0,255); }
  color: rgb(0,128,0);
}
CSSStyleRule | .box | color: rgb(255, 0, 0);
  CSSMediaRule | (min-width: 1px) |
    CSSNestedDeclarations |  | color: rgb(0, 0, 255);
  CSSNestedDeclarations |  | color: rgb(0, 128, 0);
computed: rgb(0, 128, 0)

メディアクエリの条件は満たしていますが、後ろに書いた緑が勝ちました。Dart Sass 1.105.1 も同じ順序を保つ出力になっています。

/* .box { color: red; & { color: blue; } color: green; } の Sass 出力 */
.box {
  color: red;
}
.box {
  color: blue;
}
.box {
  color: green;
}

ブラウザの版によって結果が分かれる書き方なので、宣言はルールの先頭にまとめ、入れ子のルールや @media はその後ろに書くという並べ方にしておくと、どの版でも同じ結果になります。

/* おすすめの並べ方 */
.box {
  color: green;                 /* 1. 宣言を先に */
  padding: 16px;

  &:hover { color: blue; }      /* 2. 入れ子のルール */

  @media (min-width: 768px) {   /* 3. アットルール */
    padding: 24px;
  }
}

@media・@container・@layer・@scopeのネスト

アットルールもスタイルルールの中に入れられます。アットルールの中に直接書いた宣言は、親のセレクタに対して適用されます。

@layer base, comp;
.wrap { container-type: inline-size; }

.card {
  color: rgb(1,1,1);

  @media (min-width: 600px) {
    color: rgb(2,2,2);
    .title { color: rgb(20,20,20); }
  }
  @container (min-width: 400px) {
    .title { text-decoration-line: underline; }
  }
  @supports (display: grid) {
    display: grid;
  }
  @layer comp { padding-top: 8px; }
  @layer base { padding-top: 4px; }
  @scope (&) to (.title) {
    :scope { outline-style: dashed; }
    p { outline-style: dotted; }
  }
}
<div class="wrap" style="width:500px">
  <div class="card">
    <p class="title">タイトル</p>
  </div>
</div>

画面幅 800px で読み込んだ結果です。

.card color: rgb(2, 2, 2)
.title color: rgb(20, 20, 20)
.title text-decoration-line: underline
.card display: grid
.card padding-top: 8px
.card outline-style: dashed
.title outline-style: none
アットルール ネストしたときの動き 今回の結果
@media 条件を満たすとき、中の宣言が親に当たる。さらにルールも入れられる .card と .title の色が変わった
@container 祖先のコンテナの幅で切り替わる 幅 500px のコンテナで下線が付いた
@supports 機能に対応しているときだけ当たる display: grid が当たった
@layer 宣言をそのレイヤーに入れる。順序は先頭の @layer base, comp; で決まる 後のレイヤー comp の 8px が勝った
@scope (&) で親を起点にし、to (...) で範囲の終わりを指定できる .card に dashed。範囲の境界にした .title には当たらない

@media の中を CSSOM で見ると、直接書いた宣言は CSSNestedDeclarations、ルールは & .title として保持されていました。

CSSStyleRule | .card | color: red;
  CSSMediaRule | (min-width: 600px) |
    CSSNestedDeclarations |  | color: blue;
    CSSStyleRule | & .title | color: navy;

コンポーネントのスタイルとレスポンシブ対応を1か所にまとめられるのが、アットルールをネストする利点です。

対応ブラウザのバージョン表

npm の @mdn/browser-compat-data 8.1.4(2026-10-01 付)から取り出した値です。

機能 Chrome Edge Firefox Safari iOS Safari
CSSネスト(& が必須。要素名で始められない) 112〜119 112〜119 - 16.5〜17.1 16.5〜17.1
CSSネスト(緩和後。要素名で始められる) 120 120 117 17.2 17.2
ネスト後の宣言を書いた順に扱う(CSSNestedDeclarations) 130 130 132 18.2 18.2
@container 105 105 110 16 16
@layer 99 99 97 15.4 15.4
@scope 118 118 146 17.4 17.4
@supports selector() 83 83 69 14.1 14.5
:is() / :where() 88 88 78 14 14
  • & 必須期(Chrome 112〜119、Safari 16.5〜17.1)では、.card { a { ... } } のように要素名で始まる入れ子が読み取られません。この時期の版も対象に含めるなら、& a { ... } と & を付けて書きます。
  • 緩和後(Chrome 120、Firefox 117、Safari 17.2 以降)は、& なしで要素名から始められます。Firefox は最初の対応版から緩和後の書き方に対応しています。
  • @scope は、データ上 Safari 26.0〜26.3 に「@scope 内のルールが input と textarea に当たらない」という注記があり、26.4 で解消とされています。

対象にする版の目安をまとめます。

対象にしたい環境 書き方の方針
2023年12月以降に更新された主要ブラウザ そのまま使える。& の省略も可
Chrome 112〜119 / Safari 16.5〜17.1 も含める 要素名で始めるときは必ず & を付ける
それより前の版も含める Sass などで平らな CSS に変換して配信する

@supportsによるフォールバック

ネストに対応していないブラウザでは、入れ子のルールが読み飛ばされます。土台のスタイルを平らな CSS で先に書き、ネストに対応した環境だけ上書きする形にしておくと、どちらでも表示が整います。判定には @supports selector(&) を使います。

/* 1. どのブラウザでも当たる土台 */
.card .title { color: rgb(1,1,1); }

/* 2. ネストに対応しているときだけ */
@supports selector(&) {
  .card {
    .title { color: rgb(2,2,2); }
  }
}

/* 3. ネストに対応していないときだけ */
@supports not selector(&) {
  .card .title { color: rgb(3,3,3); }
}
title => rgb(2, 2, 2)
CSS.supports("selector(&)"): true

Chromium 141 では2番のルールが当たり、JavaScript の CSS.supports("selector(&)") も true を返しました。非対応ブラウザでの動作(3番が当たること)は、今回の環境では未実行です。

広い範囲のブラウザに同じ見た目を届けたいときは、ビルドの段階で平らな CSS に変換する方法が確実です。

方法 内容 今回の確認
@supports selector(&) 対応環境だけネスト版を当てる 実行済み(Chromium 141)
Sass でコンパイル .scss で書き、平らな CSS を配信する 実行済み(Dart Sass 1.105.1)
PostCSS や Lightning CSS などの変換ツール CSSネストの書き方のまま、平らな CSS に変換する 未実行

コピペ用パターン集

次のコードは、まとめて Chromium 141 に読み込ませ、31個のルール(アットルールを含む)がすべて解釈されること(読み飛ばしがないこと)を確かめたものです。

カード(子要素・状態・レスポンシブ)

.card {
  padding: 16px;
  border: 1px solid #d1d5db;
  border-radius: 8px;

  .card-title { font-size: 1.25rem; font-weight: 700; }
  .card-text { color: #4b5563; }
  &.is-featured { border-color: #1d4ed8; }
  &:hover { box-shadow: 0 4px 12px rgb(0 0 0 / 0.12); }
  &:has(img) { padding-block-start: 0; }

  @media (min-width: 768px) {
    padding: 24px;
    .card-title { font-size: 1.5rem; }
  }
}

ナビゲーション(リンクの状態・現在のページ)

.nav {
  display: flex;
  gap: 16px;

  a {
    color: inherit;
    text-decoration: none;

    &:hover, &:focus-visible { text-decoration: underline; }
    &[aria-current="page"] { font-weight: 700; }
  }
  > li + li { border-inline-start: 1px solid #d1d5db; }
}

ボタン(状態・疑似要素・隣り合うボタン)

.btn {
  padding: 8px 20px;
  color: #ffffff;
  background: #1d4ed8;

  &:hover { background: #1e40af; }
  &:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
  &:disabled { color: #4b5563; background: #e5e7eb; }
  &::after { content: " →"; }
  & + & { margin-inline-start: 8px; }
}

& + & は .btn + .btn の意味です。ボタンを2つ並べたところ、2つ目だけに 8px の余白が付きました。

親の状態で切り替える(& を後ろに置く)

.menu {
  display: none;

  .is-open & { display: block; }
  :root[data-theme="dark"] & { background: #111827; }
  @media (prefers-reduced-motion: no-preference) { transition: opacity 0.2s; }
}

.is-open の中に .menu を置いて確かめると、display は block になりました。「祖先がこの状態のとき」という条件を、対象のルールの中に書けるのがこの形の便利なところです。

リスト(:not・:nth-child)

.list {
  li {
    padding-block: 8px;
    &:not(:last-child) { border-block-end: 1px solid #e5e7eb; }
    &:nth-child(odd) { background: #f9fafb; }
  }
}

コンテナクエリ

.panel-wrap { container-type: inline-size; }
.panel {
  display: grid;
  gap: 12px;

  @container (min-width: 480px) {
    grid-template-columns: 1fr 2fr;
    .panel-side { order: -1; }
  }
}

SassとCSSネストの違いまとめ

項目 Sass(SCSS) CSSネスト
処理される場所 コンパイル時(平らな CSS を出力) ブラウザが直接読む
&__elem などの連結 できる できない(ルールごと読み飛ばされる)
親がセレクタリストのときの詳細度 セレクタごとに展開され、個別に計算 :is() と同じで、最も高いものを採用
ネストの後ろの宣言 書いた順を保って出力(1.105.1 で確認) 書いた順のまま扱う(Chrome 130・Firefox 132・Safari 18.2 以降)
& の省略 子孫・コンビネータで省略可 同じ
要素名と親の組み合わせ div& はエラー("&" may only used at the beginning of a compound selector.) div& と書ける
変数・mixin・関数・@extend 使える ネストの機能には含まれない(変数はカスタムプロパティで代替)
@at-root・#{&} の補間 使える 使えない
配信されるファイルサイズ 展開後なので親セレクタが繰り返される 入れ子のままなので繰り返しが減る

Sass の変数や mixin を使っていないなら、CSSネストだけでコンパイルなしの構成にできます。 Sass を使い続ける場合も、Sass は入れ子を平らに展開して出力するので、そのまま広い範囲のブラウザで動きます。

つまずきやすい点と対処

起きること 理由 対処
&__elem のスタイルが当たらない 連結はできず、ルールが読み飛ばされる .block__elem { } とクラス名を書く
:hover { } で子要素までホバーに反応する & :hover(子孫)と解釈される &:hover { } とくっつける
.active { } が親自身に当たらない & .active(子孫)と解釈される &.active { } と書く
後から書いたルールで上書きできない 親のリストに ID があり、詳細度が :is() 相当で高い 親を :where() で包む、ID とクラスを混ぜない
ブラウザによって色が変わる ネストの後ろに宣言を書いている 宣言を先頭にまとめる
一部の版で a { } の入れ子だけ効かない & 必須期の版(Chrome 112〜119、Safari 16.5〜17.1) & a { } と書く
ネストが深くなりセレクタが長い 段を重ねるたびに詳細度が上がる 2〜3段までを目安にする
疑似要素のルールの中に書いた入れ子が当たらない & は疑似要素を表せない 疑似要素は一番内側に &::before { } と書く

最後の行は、.tip::before { color: rgb(1,1,1); & { color: rgb(2,2,2); } } で確かめました。入れ子の & { } はルールとしては残りますが、::before の色は rgb(1, 1, 1) のままで、入れ子の側は当たりませんでした。.tip2 { &::before { ... } } のように、疑似要素を一番内側に置く書き方は意図どおりに当たります。

エラーが表示されないまま読み飛ばされることが多いので、当たらないときは開発者ツールのスタイル欄で、そのルールが一覧に出ているかを確かめるのが近道です。

よくある質問

Q. & は必ず書く必要がありますか? A. 子孫セレクタ(.title、a)やコンビネータ(> li、+ p)で始めるときは省略できます。疑似クラス(&:hover)、疑似要素(&::before)、クラスの重ねがけ(&.active)、親を後ろに置く形(.dark &)では必要です。Chrome 112〜119 と Safari 16.5〜17.1 も対象に含めるときは、要素名で始める場合にも & を付けます。

Q. Sass の &__title が効かないのはなぜですか? A. CSSネストの & は文字列ではなく、親セレクタに当たる要素を表すためです。Chromium 141 で確かめたところ、&__elem のルールは丸ごと読み飛ばされました。.card__title { } のようにクラス名をそのまま書くか、Sass でコンパイルした CSS を配信します。

Q. CSSネストは何段まで重ねてよいですか? A. 段数に決まった上限の目安はありませんが、重ねるほどセレクタが長くなり詳細度も上がります。2〜3段までにして、それより深くなるときは別のクラスを付けて平らに書くと、後から上書きしやすくなります。

Q. Sass から CSSネストに移すとき、何を確認すればよいですか? A. &__ や &-- の連結、親に ID とクラスを混ぜたセレクタリスト、入れ子の後ろに書いた宣言の3点です。この記事の書き換え対応表に沿って直し、対象ブラウザに & 必須期の版が含まれるかをバージョン表で確かめます。

まとめ

  • CSSネストはブラウザが直接読む標準機能。Chrome 120・Firefox 117・Safari 17.2 以降は & なしで要素名からも始められる
  • 子孫・コンビネータは & を省略でき、疑似クラス・疑似要素・クラスの重ねがけ・親を後ろに置く形は & が必要
  • &__elem の連結は書けない。ルールごと読み飛ばされるので、クラス名をそのまま書く
  • 詳細度は :is() 相当。親のリストに ID があると、Sass と同じコードでも結果が変わる。抑えるなら :where()
  • ネストの後ろの宣言は書いた順のまま扱われる(Chrome 130・Firefox 132・Safari 18.2 以降)。宣言は先頭にまとめると版による差が出ない
  • @media・@container・@layer・@scope・@supports もネストできる。フォールバックは @supports selector(&) か、平らな CSS への変換で行う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CSSネストの書き方|&の使い方とSassとの違い・対応ブラウザ」

株式会社RJCでは、CSSネストをはじめとするCSSの新しい書き方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?