【CSS】カスケードレイヤーの使い方 - @layer

## 概要
CSSの新機能「カスケードレイヤー」がいよいよ主要ブラウザすべてにサポートされました。
それに伴い、カスケードレイヤーの使い方についてまとめました。

## カスケードレイヤー `@layer`とは？
カスケードレイヤーとは、**スタイルの優先順位**を**レイヤー**として管理できるようにしたCSSのアットルールです。
*※ アットルールは、`@import`や`@charset`などの`@`から始まる構文のこと*

カスケードレイヤーが登場したことで、
CSSの詳細度とスタイルの順番を明示的に階層化できるため、
`!important`だらけで、CSSが思い通りに当たらないようなカオスな状態から脱却することができます。

ただ、*「classでスタイルが当たらないから、カスケードレイヤーで当てよう」* といった気軽に当てると、
今とあまり変わらなくなるので、CSSをしっかり設計してから、反映していく必要はあります。

### 今までと何が違うの？
:::note
今までの優先度の順位にCascade Layersが追加されました。
インラインのstyle属性に記述したスタイルより優先度が低く、
IDセレクター`#id名 {...}` や要素セレクター`h1 {...}`より優先度が高くなります。
:::

そのため、カスケードレイヤーで当てたスタイルは、
`!important`で指定するより優先度が低いので、`!important`で指定したスタイルが優先されますが、
IDセレクターなどで指定したスタイルより優先されます。

|優先度|今までの優先度|これからの優先度|
|:--:|:--|:--|
|**1**|Origin and Importance|Origin and Importance|
|**2**|Context|Context|
|**3**|Element-Attached Styles|Element-Attached Styles|
|**4**|Specificity|<font color="#55C500">**Layers**</font>|
|**5**|Order of Appearance|Specificity|
|**6**||Order of Appearance|

- Origin and Importance
    - ブラウザーごとに指定されているスタイルや`!important`で指定したスタイルなどのこと
- Context
    - Shadow DOM内のスタイルなどのこと
- Element-Attached Styles
    - インラインのstyle属性に記述するスタイルのこと
- <font color="#55C500">**Layers**</font>
    - 今回追加された`@layer`内に記述したスタイルのこと
- Specificity
    - IDセレクター`#id名 {...}` や要素セレクター`h1 {...}`などのスタイルのこと
- Order of Appearance
    - classセレクタ`.class名 {...}` などのスタイルのこと


## 基本的な使い方
### １つのレイヤーのみを指定する場合
```css
/* 1.レイヤー名を定義する */
@layer レイヤー名;

/* 2.レイヤーを利用する */
@layer レイヤー名 {
  .style {
    /*任意のスタイルを記述する*/
  }
}
```
**サンプル**
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="zYRZwNX" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/zYRZwNX">
  cascade layer</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### 複数のレイヤーを指定する場合
`,`（カンマ）で区切ることで、複数のレイヤーを定義することができます。
優先度は、後に宣言したレイヤーが優先度が高くなります。
*※以下の例ではレイヤー1より、レイヤー2の方が優先度が高くなります。*
```css
/* 1.レイヤー名を定義する */
@layer レイヤー1, レイヤー2;

/* 2.レイヤーを利用する */
@layer レイヤー1 {
  /*任意のスタイルを記述する*/
}

@layer レイヤー2 {
  /*任意のスタイルを記述する*/
}
```

**サンプル**
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="yLvMboR" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/yLvMboR">
  cascade layer - sample1</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

`base`レイヤーでは赤に指定し、`foundation`レイヤーでは緑に指定している。
結果を見ると緑色になっているため、`foundation`レイヤーの方が優先度が高い

### レイヤーの中にレイヤーを指定する場合
レイヤーを入れ子にすることもできるようです。
親レイヤーの中に子レイヤーを定義しても、親レイヤーの外に定義しても、レイヤーを入れ子にすることができます。
*※ レイヤーの入れ子関係をちゃんと記述することを考えると、親レイヤーの中に子レイヤーを定義したほうが良いと思います。*

```css
/* 1.親レイヤーを定義する */
@layer 親レイヤー;

/* 2.親レイヤーを利用する */
@layer 親レイヤー {
  /* 3.子レイヤーを利用する */
  @layer 子レイヤー;
  @layer 子レイヤー {
    /*任意のスタイルを記述する*/
  }
}
```

また、このように、親レイヤーの後に`.`で子レイヤーを指定することでも子レイヤーを利用することができます。

```css
/* 1.レイヤー名を定義する */
@layer 親レイヤー;
@layer 子レイヤー;

/* 2.レイヤーを利用する */
@layer 親レイヤー.子レイヤー {
  /*任意のスタイルを記述する*/
}

```

**サンプル**
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="jOZBvXm" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/jOZBvXm">
  cascade layer - sample2</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


## ブラウザーの互換性
2022.5.18 時点では、主要ブラウザでは、問題なく使えそうです。(まだ、実験的な機能ですが...)
IEが2022.6.15でサービス終了することを考えると、使いはじめてもいいかもしれませんね！
<p class="ciu_embed" data-feature="css-cascade-layers" data-periods="future_1,current,past_1,past_2" data-accessible-colours="false">
<picture>
<source type="image/webp" srcset="https://caniuse.bitsofco.de/image/css-cascade-layers.webp">
<source type="image/png" srcset="https://caniuse.bitsofco.de/image/css-cascade-layers.png">
<img src="https://caniuse.bitsofco.de/image/css-cascade-layers.jpg" alt="Data on support for the css-cascade-layers feature across the major browsers from caniuse.com">
</picture>
</p>
<script src="https://cdn.jsdelivr.net/gh/ireade/caniuse-embed/public/caniuse-embed.min.js"></script>

## ケーススタディ
こういう場合どうなるの？と感じることがあったので、まとめました。

### レイヤー内で`!important`を使うとどうなるの？
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="dydvWjX" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/dydvWjX">
  cascade layer - case study1</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

:::note
カスケードレイヤー内で`!important`を使うと、優先度が`Origin and Importance`になりそうです。
:::

`!important`を指定しなかった場合では、ドキュメント通りインラインスタイルが優先されました。
`!important`を指定した場合では、カスケードレイヤー内で`!important`を指定したスタイルが優先されました。
予想通りです。

<br/>

### レイヤー内のクラスとレイヤー外のクラスを同じ要素に当てるとどうなるの？

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="vYdxZgp" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/vYdxZgp">
  cascade layer - case study1</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

レイヤー内のクラスとレイヤー外のクラスを比べると、
レイヤー内のクラスが優先度高いので、`.red`のスタイルが当たると思ったのですが、
`.green`のスタイルが当たってます。🤔

:::note
レイヤー外でスタイルを指定すると、無名のレイヤーとして宣言されたことになるようです。
そして、無名レイヤーは、他のレイヤーより優先度が高いようです。
:::

[こちらで](https://developer.mozilla.org/ja/docs/Web/CSS/@layer#%E5%8D%98%E7%B4%94%E3%81%AA%E4%BE%8B)解説がありました。

具体的には`@layer base, foundation;`と宣言すると、
優先度は、`無名レイヤー` ＞ `foundation` ＞ `base` の順になるようです。

## まとめ 
この記事では、カスケードレイヤーの使い方についてまとめました。

「カスケードレイヤーによって、CSS設計が変わるぞ！！」といろんなメディアで言われていましたが、
大きく変わることはなさそうかなと感じました。

現在では、FLOCSSやSMACSSといったものが優秀すぎて、
FLOCSSやSMACSSをカスケードレイヤーで表現してみたくらいで、
根本的に変わるとかは今は考えにくいです。

プロジェクトの大きさにもよりますが、
カスケードレイヤーで優先度を管理したことにしても、
大きなリファクタリングが必要になるので、導入コストも高いかもです。

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510