完全体となったContainer Queriesの所感の雑記

Chrome 111 betaでついに、Style Container Queriesが対応されました。
[Chrome 111 beta \- Chrome Developers](https://developer.chrome.com/blog/chrome-111-beta/)

今まではサイズのみ対応で、Container Queriesとして使い物になりませんでした。
しかし今回のベータ版のアップデートで `style()` 関数の対応しています。

前々からContainer Queriesは、CSS設計を変革させる機能だと思って非常に楽しみにしていました。ベータ版とはいえ、嬉しく思います。

**追記: 2023年2月18日**
まだ `style(color: #000)` 的な書き方は実装されていないので、完全体ではありませんでした。

## Container Queriesで考えていたこと
### Media Queries
「Media QueriesでCustom Propertiesを使いたい」というのをたまにTwitterなどで見かけます。
Media QueriesでCustom Propertiesを使えるようする仕様書などもあります。
ただうろ覚えなのですが、Media Queriesは独自で分離しており、:rootなどからCustom Propertiesを認識できるようにするのが大変、というのをどこかで見た気がします。
大変そうな処理なのでMedia Queriesよりも、Style Container Queriesで擬似的な実装ができないか考えていました。

```css
:root {
  --viewport: initial;
  --viewport-sm: initial;
  --viewport-md: initial;
  
  container-name: root;
}

@media (800px > width) {
  :root {
    --viewport: md;
    --viewport-md: true;
  }
}

@media (400px > width) {
  :root {
    --viewport: sm;
    --viewport-sm: true;
  }
}
```

まずは `:root`に対して、containerの名前空間を定義しておきます。 (`root`)
そしてCustom PropertiesをMedia Queriesで切り替えます。
これで下準備は完了です。
なお、ここでは `--viewport` と　`--viewport-**` の2つのCustom Propertiesを定義しています。
`--viewport` は変数の値が切り替わるので、 特定のViewportに対してCSSが適用されます。
　`--viewport-**` はその指定のViewport以下に適用するためにCustom Propertiesを分離しています。

実際の記述を見てみましょう。

```css
@container root style(--viewport: md) {
  .test {
    border: 8px solid #000;
  }
}
```

`--viewport` を指定しているので、400pxから800pxの間のみ、線が出るようになります。
もし800px以下で常に線を出したい場合は `style(--viewport-md: true)` と変えます。

まだ実験的な手法を考えて試しているだけなので、もう少しブラッシュアップが必要だと思いますが、これで擬似的にMedia QueriesをCustom Propertiesで扱うことができます。

### pre と code

自分の個人ブログでは`pre`と`code`を利用しています。
ただp要素の中の`code`は、装飾が必要ですが、`pre code`はコードハイライト用のCSSを反映させるために`code`のスタイルが不要になります。

```html
<p>自分の個人ブログでは<code>code</code>を利用しています。</p>

<pre><code>// ここの`code`のスタイルはいらない</code></pre>
```

そのため、下記のようにCustom Propertiesのinitialテクニックを使用して、`pre code`の場合はスタイルを表示させないようにしています。

```css
code {
  --_code: initial;
  background: var(--_code, var(--color-gray-pale));
  border-radius: var(--_code, 4px);
  padding-block: var(--_code, 0.2em);
  padding-inline: var(--_code, 0.4em);
}
pre code {
  --_code: ;
}
```

ただContainer Queriesを使用すれば、もっとよくなりそうです。
試しに書きかえてみましたが、下記のコードでは動きませんでした。

```css
code {
  --el-code: true;
  container-name: code;
}
pre code {
  --el-code: false;
}

@container code style(--el-code: true) {
  code {
    background: #eee;
    border-radius: 4px;
    padding: 0.2em 0.4em;
  }
}
```

上記のコードが動かない理由として、`code`をContainer Queriesの「コンテナ」になってしまったからのようです。`code`要素の中に`code`要素が入っていれば、子の`code`要素のスタイルが変化しますが、コンテナになったセレクタはcontainerの基準になってしまうため、@containerQueries の適用範囲から外れてしまうようです。(`this`的なものが欲しい...)

そのため下記のように書きかえれば動作しますが、綺麗ではないですね。

```css
:is(p, table) {
  --el-code: true;
  container-name: text;
}

@container text style(--el-code: true) {
  code {
    background: #eee;
    border-radius: 4px;
    padding: 0.2em 0.4em;
  }
}
```

`pre`要素の`code`要素にスタイルが当たらないようにするなら、`:not()`で良くない？と思い直して書きかえました。
下記の方がスマートだし、Container Queriesいらんかった。

```css
:not(pre) > code {
  background: #eee;
  border-radius: 4px;
  padding: 0.2em 0.4em;
}
```

### pre と code の失敗から
Container Queriesの指定先は変化させることができない、という制限があるようなので使い所が難しいと思っていたのですが、ふと思いつきました。

CSSをコンポーネントでScopeできるんじゃね？

まずは適当なHTMLを用意します。

```html
<div class="a">demo</div>

<div class="card">
  <div class="a">demo</div>
</div>
```

CSSは下記です。

```css
:root {
  --scope: true;
}

.card {
  container-name: card;
}

@container card style(--scope: true) {
  .a {
    background: #faa;
    border-radius: 4px;
    margin: 1em 0;
    padding: 0.2em 0.4em;
  }
}
```

![スクリーンショット 2023-02-13 10.43.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/5273ee6e-8d07-50cb-6b1f-776077c4d9ac.png)

`.card` のコンポーネントの中で Scope できました。

HTMLの要素をさらに増やします。

```html
<h2 class="title">title</h2>
<div class="a">demo</div>
<p>本文のダミーテキスト</p>


<div class="card">
  <h2 class="title">title</h2>
  <div class="a">demo</div>
  <p>本文のダミーテキスト</p>
</div>
```

CSSは下記。

```css
:root {
  --scope: true;
}

.card {
  container-name: card;
  border: 1px solid #000;
  padding: 1em;
}

@container card style(--scope: true) {
  .title {
    margin: 0;
    font-size: 1rem;
  }
  .a {
    background: #faa;
    border-radius: 4px;
    margin: 1em 0;
    padding: 0.2em 0.4em;
  }
  p {
    margin: 0;
    color: #aaa;
  }
}
```

![スクリーンショット 2023-02-13 10.48.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/ef766a40-3dc0-a3e7-b135-fbd04d0df7a9.png)

Container Queriesは名前空間も設定できるので、コンポーネントごとに　`container-name`プロパティを設定しておけば、Scopeとして扱うことができます。

Container Queriesは、まだChromeのベータ版しか対応されていませんが、やはり今後が楽しみな技術でした。