【初心者向け】CSSが思い通りに適用される新機能「@layer」と「@scope」

## はじめに

この記事は、「うぇーん、CSSのスタイルがなんか上書きされちゃて、どのクラスが当たっているのかわかんないよぉ」と嘆くみなさんに送ります。この記事の半分は優しさでできています。

難しいですよね、CSS。多くのフロントエンドエンジニアの方でも、CSSは誤魔化しで生きています。特に、どのクラスが当たっているかわからなくなりますよね。margin設定しているのに指定通りのmarginにならなかったり、font-sizeが指定した通りにいかなかったり。

そんなあなたに朗報です。CSSに新たな機能が追加されました！それが、**@ layer** と **@ scope**です！この機能を駆使すれば、優先度を自由自在に操れます。これでもう、「どのスタイルが効いているかわからない」とか、「とりあえず!importantにしまくったらどれが優先されているかわからなくなっちゃった」というのもおさらばです。

※@ scopeに関しては2023年時点では、ChromeおよびEdgeのみ利用可能なプロパティです。

## @ layerとは

https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/Cascade_layers

@ layer、カスケードレイヤーとは、簡単に説明すると、CSSのスタイル群を一つのレイヤーにしてしまうという画期的な技術です。

例えば、以下のようなスタイルがあるとします。

```css:style.css
.card {
    width: 300px;
    margin-left: 16px;
    margin-right: 16px;
    background-color: white;
}

.title {
    font-size: 20px;
    font-color: #333;
    font-weight: bold;
    line-height: 24px;
}

```
通常のスタイルですね。これをカスケードレイヤーにすると、こうなります。
```css:style.css
@layer hoge {
    .card {
        width: 300px;
        margin-left: 16px;
        margin-right: 16px;
        background-color: white;
    }

    .title {
        font-size: 20px;
        font-color: #333;
        font-weight: bold;
        line-height: 24px;
    }
}
```
というような形になります。ただ単に、`@layer レイヤー名`で囲ってあげるだけです。何も難しいことはありません。これで囲ってあげるだけで、この場合だったら`hoge`というレイヤーになります。

## レイヤーにすると何が嬉しいのか

レイヤーになるってことまではわかったけど、じゃあレイヤーにすると何が嬉しいのか。それは、**レイヤー同士で優先度を決められる**ということです。例えば、デフォルトでは`button`や`input`は、元々のスタイルをリセットして、自分でカスタマイズしたスタイルにしたいと言う時、こんな感じになります。
```css:style.css
@layer reset,base
@layer reset {
    button {
      padding: 0;
      margin: 0;
      font: inherit;
      color: inherit;
      background: none;
      border: none;
    }
    input {
      padding: 0;
      margin: 0;
      font: inherit;
      color: inherit;
      background: none;
      border: none;
    }
} 
@layer base {
    button {
      font-weight: bold;
      font-size: 14px;
      color:white;
      background-color:blue;
    }
    input {
      font-size: 14px;
      border: solid 1px yellow;
    }
}
```
**この使い方が、@ layerで最も重要な部分です。** 使い方としては、今回`reset`と`base`という二つのレイヤーがあります。二つ以上ある場合、`@layer reset,base`と並べることによって優先度が決められちゃいます。右側にいけば優先度が高くなります。この並べ方によって優先度が決められるので、他のレイヤーを増やしたとしても、この並び順さえ変えてしまえば優先度を好きに決められます。非常にすばらしいですね。外部ファイルのCSSに関しても,`@import url("style2.css") layer fuga`のように`@import`構文を使えばレイヤー化できます。

## ただしレイヤー化されていないスタイルは一番優先度が高い
レイヤー化されいないスタイルは、最も優先度が高くなります。これを逆手に取れば、リセットCSSなど優先度を低くしたいものに関してはレイヤー化させれば低くできます。そして個別にちょっとあてたいスタイルがあれば、別にレイヤー化していなくても優先度が高く設定されます。

例えば、`CSS in JS`を使っている場合、細かいスタイルをレイヤー化するのは難しいので、大枠だけレイヤー化させて、細かいスタイルはそのまま書けば思い通りにスタイルを当てられます。

以上が　`@layer`のご紹介でした。

## 適用範囲を狭められる`@scope`

こちらは、CSSの適用範囲を限定できるという画期的なCSSの新しいプロパティです。
今までだと、それぞれのクラスにスタイルを当てるために、`CSS in JS`を使ったり、`BEM記法`などのCSS設計を行ったりしてクラス名が一意になるように頑張らなければいけませんでした。クラス名がバッティングしてしまと、どこで定義したスタイルが適用されているのかわからなくてってしまうからです。

それが、`@scope`を使うと、スタイルの適用範囲を制限できるため、あちらこちらにスタイルが適用されてしまうという事故が防げるんです！

## 使い方

大まかなコンポーネントに一意的なクラス名を与えてあげます。大まかなコンポーネントとは、`<main>~</main>`や、`<div>~</div>`など、そのページやなんらかのパーツ全体のことを指しています。

そして、 `@scope`を適用してあげます。

```style.css
@scope (.container) {
    :scope {
      margin-inline: 8px;
      background: #f6f8fa;
    }
    p {
      font-size: 14px;
      line-height: 16px;
    }
    h2 {
      font-size: 16px;
      line-height:18px;
    }
}
```

ポイントは、適用範囲を制限したいトップに、一意のクラス名を当てて、`@scope (クラス名)`で中身を定義してあげるところです。これで、例えばこの例だったら`.container`より外にはこのスタイルは適用されません。無駄に大変なクラス名を考える必要も、乱数でクラス名を生成する必要もありません。ちなみに、この`:scope`は、そのスコープ内での`:root`と同じ意味です。そのクラス内にのみ適用されます。

クラス名の命名規則に関しては自由ですが、ここだけはバッティングしてはいけません。そうすると`@scope`の意味がないですから。自分としての提案は、ページ名やコンポーネント名は絶対にバッティングすることがないので、その名前のクラス名を与えてあげればいいと思います。

あまりに細かく`@scope`を当てると、`@scope`を使っている意味がないので、なるべく大きく使いましょう。

## 近接度のおかげで、`@scope`内のクラスに`@scope`を書いても大丈夫

例えば、`.container`クラスの中に`.card`があって、その中はフォントサイズを小さくして、色も変えたいというとき、その`.card`にも`@scope`を適用してあげましょう。
```style.css
@scope (.container) {
  /*　略 */
}

@scope (.card) {
  p {
     font-size:12px;
  }
}
```

このようにしてあげます。HTMLとしては以下のようになっていますね。
```index.html
<div class="container">
 <div class="card">
     ...
 </div>
</div>
```
これをみてあれって思うかもしれません。「結局、`.container`の中に`.card`があったら何が適用されるのかわからなくなるじゃん」と。

しかしそれは心配ご無用。`@scope`には、**近接性**という、近い方の`@scope`のスタイルが適用されるというルールがあります。これによって、`.card`内は`.card`のscopeで定義されたスタイルが優先されます。これで心配せずに`@scope`でスタイルを定義できますね。

## そこだけはスタイルを当てないってこともできる

例えば、`.container`のスコープにたくさんスタイルを当てたけど、`.hoge`内だけはそれをすべて避けたい時、`.hoge`に`@scope`を当てて全部打ち消した上でスタイルを当てるということも可能ですが、その`.hoge`だけはスタイルを当てないみたいなこともできます。

```style.css
@scope (.container) to (.hoge) {
    /* 何かしらのスタイル */
}
```
と書くと、`.hoge`だけはスタイルが適用されなくなります。この書き方を**ドーナツスコープ**と呼びます。ドーナツみたく間をあけてスタイルを当ててるからですね。部分的にスタイルを避けたいときにとても便利です。またあまりに多くドーナツスコープを当てたいときは、そもそも共通化すべきでないものが共通化されているので、見直してあげましょう。そしてその避けたい部分にちゃんと`@scope`を当ててあげましょう。


## 終わりに

いかがでしたでしょうか。CSSの機能が信じられないくらいに進化しました。`@scope`は出てきたばかりの機能で対応ブラウザもまだ少ないですが、間違いなくこれから絶対必須の機能です。
今までJavaScriptを駆使しないとできなかったようなことがCSSだけでかなりできるようになりました。みなさんもぜひ、`@layer`と`@scope`を使ってみてください！

途中で書いてて気づきましたが、QiitaのCSSのコードハイライトがちゃんとat ruleに適用されましたね。