LoginSignup
7
2

More than 1 year has passed since last update.

CSS Nestingを試してみる

Last updated at Posted at 2022-11-25

Google Chromeの実験的な機能として、CSSのネストが実装されたらしいということで、仕様を読みながら実際にその挙動を確認してみようと思います。

本記事で紹介する「CSS Nesting Module」の仕様は現時点(2022/11/25)でFirst Public Working Draft(2022/8/31公開)であり、今後仕様が変更される可能性があります。

実験的な Web プラットフォームの機能
本記事の内容を確認するためにはchrome://flags/にアクセスして、Experimental Web Platform featuresEnabledにする必要があります。

現状の対応ブラウザ:https://caniuse.com/css-nesting

CSS Nesting Module

CSS Nesting ModuleはネイティブCSSでネスト(入れ子)を導入するための仕様です。
CSSでネストを使うためには、今までSassやLess、StylusなどのCSSプリプロセッサを導入する必要がありました。CSS Nesting Moduleがブラウザに実装されると以下のようなコードをネイティブのCSSで実現できます。

.parent {
    color: red;
    & > .child {
        color: bluel
    }
}

/* 以下のコードと同等に解釈される
.parent {
  color: red;
}
.parent > .child {
  color: blue
}
*/

挙動を試してみる

以下の挙動はFirst Public Working DraftだけではなくEditor’s Draftの内容も参考にしています(個人的に試した限りだと「Editor’s Draft」の内容も反映されているようでした)。
参考:https://bugs.chromium.org/p/chromium/issues/detail?id=1095675

基本的なネスト

例えば次のようなコードがあるとします。

<div class="parent">
    parent
    <div class="child">child</div>
</div>
.parent {
  color: red;
}
.parent .child {
  color: blue
}

このCSSをネストで表現しようとすると、次のように書くことができます。Sassユーザーには見慣れた形ですね。

.parent {
  .child {
    color: red;
  }
}

もしくは&を使って次のように書くこともできます。

.parent {
  & .child {
    color: red;
  }
}

ChromeのExperimental Web Platform featuresEnableにして確認すると、次の画像のようにスタイルが適用されることを確認できました。

base-sample.png

要素型セレクター

要素型セレクターをネストで指定するときには&をつける必要があります。もしくは:is()使っても問題ありません。

要素型セレクターとは簡単にいうとh1pなどの要素をそのまま指定したセレクターのことです。
参考:要素型セレクター - CSS: カスケーディングスタイルシート | MDN

<ul>
  <li>item - 01</li>
  <li>item - 02</li>
  <li>item - 03</li>
</ul>
ul {
  & li {
    color: red;
  }
  /* もしくは以下でもいい */
  :is(li) { 
    color: red;
  }
}

/* 以下のコードと同等
ul li {
  color: red
}
*/

/* 以下はNG
ul {
  li {
    color: red
  }
}
*/

type-selector-sample.png

複数のネスト

複数ネストも可能です。

<div class="hoge">
  hoge
  <div class="fuga">
    fuga
    <div class="piyo">piyo</div>
  </div>
</div>
.hoge {
  color: red;
  .fuga {
    color: blue;
    .piyo {
      color: green;
    }
  }
}
/* 以下と同等
.hoge {
  color: red;
}
.hoge .fuga {
  color: blue;
}
.hoge .fuga .piyo {
  color: green;
}
*/

muti-nest-sample.png

隣接セレクタ

隣接セレクタは次のように書くことができます。

<ul class="list">
  <li class="item">item - 01</li>
  <li class="item">item - 02</li>
  <li class="item">item - 03</li>
</ul>
.item {
  + .item {
    color: blue;
  }
}
/* 以下と同等 
.item + .item {
  color: blue;
}
*/

adjacent-combinator-sample.png

擬似クラス

次のように書くことで擬似クラスのまとめることができます(例として:nth-childを使用していますが、:hover:focusなどでも同様です)。

<ul>
  <li>item - 01</li>
  <li>item - 02</li>
  <li>item - 03</li>
</ul>
ul {
  & li {
    color: red;
    &:nth-child(2) {
      color: blue;
    }
    &:nth-child(3) {
      color: green;
    }
  }
}
/* 以下と同等 
ul li {
  color: red;
}
ul li:nth-child(2) {
  color: blue;
}
ul li:nth-child(3) {
  color: green;
}
*/

pseudo-classes-sample.png

擬似要素

擬似要素も擬似クラスと同様にまとめることができます。

<div class="hoge">hoge</div>
.hoge {
  &::before {
    content: "before - ";
  }
  &::after {
    content: "- after";
  }
}
/* 以下と同等
.hoge::before {
  content: "before - ";
}
.hoge::after {
  content: "- after";
}
*/

pseudo-element-sample.png

1つの要素に複数のセレクタ

1つの要素に複数のセレクタを適用したいときは&を使って次のように書くことができます。

<div class="fuga">fuga</div>
<div class="fuga hoge">fuga and hoge</div>
.fuga {
  color: red;
  &.hoge {
    color: blue
  }
}
/* 以下と同等
.fuga {
  color: red;
}
.fuga.hoge {
  color: blue;
}
*/

compound-selector.png

&を連続で複数使う

あまり使うことはないかもしれませんが、&を連続で使うこともできます。詳細度を上げるテクニックとしては有効ですが、決して乱用するものではありません。
参考:セレクターの複製による詳細度の向上

<div class="fuga">fuga</div>
.fuga {
  color: red;
  && {
    color: blue;
  }
}
/* 以下と同等
.fuga {
  color: red;
}
.fuga.fuga {
  color: blue;
}
*/

continue-ampersand.png

:not&を使う

:not&を使うことで、次のようなコードも可能です。

<div class="hoge">hoge</div>
<div class="fuga">fuga</div>
.hoge {
  color: red;
  :not(&) {
    color: blue;
  }
}
/* 以下と同等
  .hoge {
    color: red;
  }
  :not(.hoge) {
    color: blue;
  }
*/

not-sample.png

Sassの@at-rootの代替

次のようなコードでSassにおける@at-root的な使い方も可能です。

<div class="hoge">hoge</div>
<div class="fuga">
  <div class="hoge">fuga > hoge</div>
</div>
.hoge {
  color: red;
  .fuga & {
    color: blue;
  }
}
/* 以下と同等
.hoge {
  color: red;
}
.fuga .hoge {
  color: blue;
}
*/

at-root-sample.png

メディアクエリー

次のように書くことで@mediaのネストも可能です。

 <div class="hoge">hoge</div>
.hoge {
  color: red;
  @media (min-width: 900px) {
    color: blue;
  }
}
/* 以下と同等
.hoge {
  color: red;
}
@media (min-width: 900px) {
  .hoge {
    color: blue;
  }
}
*/

また@mediaの中に@mediaをネストすることもできます。

.hoge {
  color: red;
  @media (min-width: 900px) {
    color: blue;
    @media (max-width: 1200px) {
      color: green;
    }
  }
}
/* 以下と同等
.hoge {
  color: red;
}
@media (min-width: 900px) {
  .hoge {
    color: blue;
  }
}
@media (min-width: 900px) and (max-width: 1200px) {
  .hoge {
    color: green;
  }
}
*/

詳細度に関して

通常、ネストを使用すると詳細度を高めることにつながります。

つまり次のコードでは.fugacolor:blueが適用されることになります。

<div class="hoge">
  <div class="fuga">fuga</div>
</div>
.hoge {
  .fuga {
    color: blue;
  }
}
.fuga {
  color: red;
}
/* 以下と同等になるので.fugaは`color:blue`が適用される
.hoge .fuga {
  color: blue;
}
.fuga {
  color: red;
}
*/

nest-specificity.png

:where()の擬似クラス関数を使うことで、これを回避することができます。

.hoge {
  :where(&) .fuga {
    color: blue;
  }
}
.fuga {
  color: red;
}
/* 以下と同等になるので.fugaは`color:red`が適用される
:where(.hoge) .fuga {
  color: blue;
}
.fuga {
  color: red;
}
*/

nest-specificity-where.png

:where()を使うと詳細度を0に保つことができます。詳しくは以下をご参照ください。
:where() - CSS: カスケーディングスタイルシート | MDN

ネストと優先順位

.hoge {
  & {
    color: red;
  }
}
.hoge {
  color: blue;
}

上記のコードを書いたときに&{}は詳細度を高めないので、後ろに書いたcolor:blueが優先されます。
感覚的にもこれは問題ないように思えますね。

しかし、次ようなコードを書いたときには注意が必要です。

<div class="hoge">hoge</div>
.hoge {
  color: red;
  & {
    color: blue;
  }
  color: green;
}

/* 以下と同等 `&{}`が優先される
.hoge {
  color: red;
  color: green;
  color: blue;
}
*/

nest-order-sample.png

通常の宣言とネストされた宣言を混合して書くと、ネストされた宣言が優先されることに注意しましょう。またこの時、詳細度は変わりません。

セレクタの一部を&で繋げる

BEMで見かける記法ですねですね。block__element--modifierelementmodifier&で繋げていく記法になります。これはできませんのでご注意ください。

<div class="block">
  block
  <div class="block__element">block__element</div>
</div>
.block {
  color: red;
  /* 以下はSassと同等の挙動ではない */
  &__element {
    color: blue;
  }
}
/* Sassでは以下となる
.block {
  color: red;
}
.block__element {
  color: blue;
}
*/
/* CSS Nesting Moduleでは以下のように解釈されるらしい
.block {
  color: red;
}
__element.block {
  color: blue;
}
*/

slector-ampersand-sample.png

おわりに

CSS Nesting Moduleの仕様は現時点ではFirst Public Working Draftであり、今後仕様が変更される可能性は十分にあります。Editor’s Draftを読んでみても、まだまだ不安定な箇所があり、この段階で一喜一憂するものではないでしょう。
とはいえ、CSS Nesting Mdduleが導入されることでコードがクリーンになったり、楽になる部分もあると思いますので、各々のブラウザでサポートされるのが待ち遠しいですね。

また、PostCSSのプラグインを使うことで、現時点でもCSS Nesting Moduleの機能を導入することが可能です。興味がある方は以下のリンクをご参照ください。
PostCSS Nesting

参考

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2