今回はCSSのネストについて解説します。
従来はSass(SCSS記法)などのCSSプリプロセッサを利用してネスト構造を利用していましたが、2023年にChromiumベースのブラウザが初めて対応し、2025年現在ではほとんどの主要ブラウザで利用できるようになっています。
目次
基本の書き方
Sass (SCSS記法)などのように入れ子で書くことができ、ブラウザが直接解釈します。
<div class="message">
メッセージの全体は1.2rem
<p class="em">ここだけ2remに</p>
</div>
上記のHTMLにCSSを適用するには、ネストを利用しない場合は以下のように記述します。
.message {
font-size: 1.2rem;
}
.message .em {
font-size: 2rem;
}
ネストを利用した方法だと以下のようにスッキリ書けます。
.message {
font-size: 1.2rem;
.em { font-size: 2rem; }
}
どちらも出力結果は同じですが、ネストの方が「どの要素の内側の指定か」が直感的に伝わります。
サンプル
ネストの中にもネストを書くことができます。
.card {
.contents {
.mark-main {
font-size: .6rem;
}
}
}
メディアクエリなどの条件付きグループ(@media
/ @supports
/ @container
など)も内側に書けます。
.card {
display: grid;
grid-template-columns: 1fr;
@media (width >= 768px) {
grid-template-columns: 1fr 2fr;
}
}
擬似クラスなど“親と結合”するケースでは &
を使います。
.card {
&:hover { box-shadow: 0 0 8px; } /* => .card:hover */
&::before { content: ""; } /* 擬似要素は & を付ける */
}
コンビネータ・結合子(要素どうしの関係を指定する記号)も内側に書けます。
.card {
.title { font-weight: 700; } /* => .card .title */
> a { text-decoration: none; } /* => .card > a */
+ .card { margin-top: 1rem; } /* => .card + .card */
~ .card { opacity: .8; } /* => .card ~ .card */
}
古いブラウザ/Safari・iOSへの対応
ネストしたCSSが効かない理由として、古いブラウザや、Safari/iOS/iPadOSのバージョンが古い可能性があります。
古いブラウザにも対応する必要がある場合は、従来通りビルド変換(変換ツール)を使います。
ビルド変換(変換ツール)を使う
CSSのネストは最新の主要ブラウザには対応していますが、古いブラウザ にも対応する必要がある場合には、従来通りSassや、PostCSS、Lightning CSS などのCSSプリプロセッサで通常のCSSに変換して配信ください。
ここでは詳しく解説しませんが、以下のツールを利用します。
- Sass(Dart Sass)
そのまま SCSS記法 のネストで書けて、ビルド時にフラットCSSへ展開されます。CLI:npm i -D sass → sass src/main.scss dist/main.css --style=expande
webpack:sass-loader + css-loader
gulp:gulp-sass(Dart Sass) - PostCSS
postcss-nesting を使うと、ネイティブのCSSネストの書式に近い形で記述でき、出力をフラット化できます。
webpack/postcss-loader や gulp-postcss に組み込み可。 - Lightning CSS
対象ブラウザに合わせてネストを自動ダウングレード(単体/webpack でも利用可)。
なお、主要ブラウザがCSSネスト対応を開始した各バージョンとリリース日は以下となっています。
ブラウザ | 対応開始 バージョン | リリース日 | 備考 |
---|---|---|---|
Chrome (デスクトップ) | 112 | 2023-04-04 | 112–119 は部分対応(先頭に記号が必要)、120+ で完全対応 |
Chrome(Android) | 120 | 2023-12-05 | モバイルもデスクトップと同様 |
Edge (デスクトップ) | 112 | 2023-04-04 | Chrome (デスクトップ)と同様 |
Edge (Android) | 120 | 2023-12-19 | モバイルもデスクトップと同様 |
Safari (macOS) iOS/iPadOSの各ブラウザ | 16.5 | 2023-05-18 | 16.5–17.1 部分対応/17.2+ で完全対応 |
Firefox (デスクトップ) Android版も同様 | 117 | 2023-08-29 | 117+ で完全対応 |
Samsung Internet | 25 | 2024-04-24 |
また、現状のブラウザのバージョン別の利用数は以下のサイトなどから確認できます。
[Edit Chart Data] から各データや表を変更できます。
https://gs.statcounter.com/browser-version-market-share/all/japan
Safari(16.5〜17.1)への対応
Safari(WebKit:iOS/ iPadOS 16.5〜17.1にインストールした各ブラウザも含みます)は、16.5からCSSのネストに対応しましたが、Safari(16.5〜17.1)は「タグ名で始まるネスト」は解釈しない(&
なしでは解釈されない)という制限がありました。
例:h2 { … }
)を & h2
にしないと解釈されない
17.2以降は問題ありません。
iOS Safari も同様です。iOS/ iPadOS の Chrome/Firefox/Edge も WebKit のため同じ仕様に従います。
16.5〜17.1の古いバージョンのSafariも対応する必要がある場合は、& h2
など &
を明示すればより安全です。
なお、クラス/ID/結合子(>
, +
, ~
)で始まる場合は &
不要です。
対応する必要がある場合は以下のように前に&をいれます。
.article {
& h2 { margin: .2rem; } /* => .article h2 */
&::before { content: ""; } /* => .article::before */
.title { padding: .2rem; } /* => .article .title */
#contents { margin: .2rem; } /* .article #contents */
> h2 { margin: .5rem; } /* => .article > h2 */
+ .article { margin-top: 1rem; }
}
iOSとiPadOSのバージョン別利用率は以下などから確認できます。
https://developer.apple.com/jp/support/app-store/
CSSネストのデメリット
古いブラウザの対応が必要
最新の主要ブラウザのみ対応するのなら問題なく利用できますが、古いブラウザまで対応する必要がある場合は、前述の通りに対応しましょう。
深いネスト構造は読みづらくなる
あまり深いネスト構造にしてしまうと、保守や可読性が低減します。
ネストは適度な深さにとどめ、読みやすさを優先しましょう。
まとめ
いかがでしょうか?
現状ではまだCSSでネストをやるには少し不安があるかもしれませんね。
多くのプロジェクトでは何らかの CSS プリプロセッサ/ビルド変換を使っていることがほとんだと思いますが、当面はSassや PostCSS(postcss-nesting)や Lightning CSS で変換するのが安全策です。
ネスト以外にも、Sass には mixin・変数・関数(@use
/ @forward
含む)などの成熟した機能があり、PostCSS でも Autoprefixer や postcss-preset-env / postcss-custom-media などで未来仕様の前倒しや最適化が行えます。
ただし、今後は旧環境の自然減に伴い、ビルドに頼らずネストをそのままCSS配信する運用も現実的になります。
ビルドに頼る必要もない、ちょっとしたCSSを書く際に、本記事で紹介したポイントを思い出していただけると幸いです。
他にもこんな記事があります。