CSSのGridをカジュアルに使いたい（雑記）

思ったままに記述と検証を繰り返した記事です。

---

CSSのGridといえば、縦軸と横軸を決め、それあわせてボックスを配置できる技術です。`grid-template-rows / columns` や `grid-template-areas` を使って、ごにょごにょします。
しかしこれらを使用する場合は、限定的なレイアウトをしっかり組みたい時に利用する場合が多いと思います。

もっとカジュアルにGridが使いたいので、少し考えてみました。

## ナビゲーションとか

![スクリーンショット 2022-12-07 0.08.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/505ad998-76ed-db88-179d-1c4040a37837.png)

ナビゲーションの子同士でスペースが必要な場合があります。
今までなら「:first-child　を使った　marginの打ち消し」や「隣接セレクタ」でmarginを取っていました。

Gridとgapを使えば、簡単に子同士のスペースは簡単に開きます。
`display: grid;` と指定すれば一見通常フローの並びになりますが、子はGridコンテナになるので楽に指定できます。

```css
ul {
  display: grid;
  gap: 16px;
}
```

もちろん Grid は、論理プロパティに対応しているので、幅も `inline-size` にしておけば、 `writing-mode: vertical-rl;` が必要になっても綺麗に並んでくれます。

![スクリーンショット 2022-12-07 0.21.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/d717455d-ebb3-3239-1302-8194dd149105.png)

## 全体として使う

Gridは、左にナビゲーションがあって、右がコンテンツで〜〜〜といった少し凝ったレイアウトに使うというイメージがありました。
ただよくよく考えると、もっと柔軟に考えてもいい気がしてきました。

![スクリーンショット 2022-12-07 0.31.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/ac975ea0-e10c-9541-132e-82820ee29e86.png)

上記は見た目は簡素ですが、よくあるサイトを囲ったりするコンテナです。
下記は、その宣言ブロックのCSSです。

```css
.container {
  max-width: 800px;
  margin: auto;
  border: 1px solid #000;
}
```

よく使われている　margin　で中央に寄せる方法の弱点としては、広がったコンテンツの対応が少し気持ち悪いです。

![スクリーンショット 2022-12-07 0.42.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/3fc2a069-1933-5949-3e22-24210ad6be9d.png)

__HTML__
```html
<div class="container">
　　lorem...
  
　　<div class="full">
 　　lorem...
　　</div>

　　lorem...
</div>
```

__CSS__

```css
html {
  overflow-x: hidden;
}

.full {
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
}
```

コンテンツが viewport を超える時にスクロールバーが出るのですが、その時に横スクロールが発生します。それを表示させないように html に `overflow-x: hidden;` の指定が必要になります。ちなみに単位は `vw` から　`svw` に変更してもダメです。
ちょっと嫌です。

これも Grid ならいけるんじゃないかと思いました。
body要素に対して、Grid をそのまま適用します。

![スクリーンショット 2022-12-07 1.27.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/9e0eb55f-c5e9-b8b4-01af-9397ebc1e189.png)

__HTML__

```html
<body>
  <div>
    lorem...
  </div>
  <div class="full">
    lorem...
  </div>
  <div>
    lorem...
  </div>
</body>
```

```css
body {
  display: grid;
  grid-template-columns: 1fr min(100%, 800px) 1fr;
  margin: 0;
}

body > * {
  grid-column: 2;
}
```

こうすれば、body直下の要素が文脈から外れなければ、疑似的な `max-width & margin: auto` が可能になります。
ただ `.full` の箇所が、画面いっぱいに広がっていません。
CSS を調整します。

![スクリーンショット 2022-12-07 1.43.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/1d5a6b6c-68e7-8d3c-5e7c-cb915db07596.png)

```css
:root {
  --container: 800px;
}

body {
  display: grid;
  grid-template-columns: 1fr min(100%, var(--container)) 1fr;
  margin: 0;
}

body > * {
  grid-column: 2;
}

.full {
  grid-column: 1 / -1;
  padding-inline: max(0px, (100% - var(--container)) / 2);
}
```

container のサイズは CSS 変数化し、 `.full` の時に body要素いっぱいに広がるようにして、padding で計算し直しました。 vw でないので、横スクロールも発生しません。

---

ここまで書いてたら、同じような Grid の使い方を提案している記事が流れてきました。
[CSS Gridで実装すると簡単！ コンテンツは中央配置、最大幅・全幅・ちょい広めのレイアウトを実装できるテンプレート \| コリス](https://coliss.com/articles/build-websites/operation/css/layout-breakouts-with-css-grid.html)

確かに線名をつけるとわかりやすさが、違いますね。
先ほどのものを修正します。

```css
:root {
  --container-size: 800px;
  --container-grid: min(100%, var(--container-size));
}

body {
  display: grid;
  grid-template-columns: 
    [full-start] 1fr
    [container-start] var(--container-grid) [container-end]
    1fr [full-end];
  margin: 0;
}

body > * {
  grid-column: container;
}

.full {
  grid-column: full;
  padding-inline: max(0px, (100% - var(--container-size)) / 2);
}
```

`grid-column` を線名にすることによって、わかりやすくなりました。

ただ `body > * { grid-column: container; }` は、body要素の直下にある要素を対象とします。bod要素直下なので、プレーンテキストをそのまま配置すると、匿名gridコンテナが生成されて Grid のルールに則ったレンダリングになります。
しかし匿名gridコンテナは、要素ではないので理想とする配置にはなりません。

__右下にプレーンテキストが押し込まれる__
![スクリーンショット 2022-12-07 10.25.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/9f379c75-cc92-eecf-d984-98c6eccdaee0.png)

body要素だから、プレーンテキストをそのまま配置するというこはあまりしませんが、この手法を子要素で行なった時に、意図しないレイアウトになりそうです。

汎用性や条件などを考えると、Grid をカジュアルに使ってる感じはしません。
`max-width & margin: auto` の方がわかりやすいですね。
ただ、こういう手法も引き出しに入れておくだけで、レイアウトの表現方法に幅が出そうです。

### Grid は関係ないけど、思いついた

画面いっぱいの広がる下記の宣言ブロックですが、 viewport を基準にするから、横スクロールが出る。

```css
/* いつもの */
.full {
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
}
```

なら Container Queries を使えばいい気がしてきました。

![スクリーンショット 2022-12-07 2.14.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/b19949c5-b7fd-5775-15cc-2b87e264c5e7.png)


```css
/* Container Queries */
body {
  margin: 0;
  container: body / inline-size;
}
.container {
  max-width: 800px;
  margin: auto;
  border: 1px solid #000;
}

.full {
  margin-inline: calc(50% - 50cqi);
  padding-inline: calc(50cqi - 50%);
}
```

まずは、body のコンテンツ幅を Container Queries の基準として、 `cqi` 単位に変更して対応してみました。
横スクロールも出ずに対応できました。

ただ残念ながら、現在は　`container-name` のフィルタリングがうまく機能していません。
というか `@container` の実装はサイズ（　`@container (width > 400px)`　こういうの） しか実装されていません。

そのため `.full` の親要素に `container` プロパティを指定してしまうと、 body 要素の　`container`　が上書きされてしまいます。

![スクリーンショット 2022-12-07 2.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75375/a3157bec-92d8-4bcf-b702-9b4f5e5dd46d.png)

```css
body {
  container: body / inline-size;
}
.container {
  container: inline-size;　/* 現状 body を上書き */
}
@container body { /* 効かない */
  .full {
    margin-inline: calc(50% - 50cqi);
    padding-inline: calc(50cqi - 50%);
  }
}
```

Container Queries の考え方自体は2015年から発表されており、Every Layoutの思想の登場、そして Chrome を中心に `@container` が実装され始めています。
Container Queries が仕様通りに対応された時の実装は、色々と面白くなりそうで、今から楽しみです。

## subgrid

body を Grid にするやつで、Chrome にも subgrid が来たら、body 要素を12分割ぐらいに分けて内部で subgrid を使ってレイアウトするのもできるかもしれません。
シンプルなデザインであれば、そういうものできそう。
ただ Grid だらけになるので、通常フローの意識を完全に Box Alignment Module　の意識へ切り替えないと大変そうです。

今のノーコードツールのレイアウトも通常フローを切り捨てて、Box Alignment Module に依存したレイアウトを強要するツールをいくつか見かけます。プレーンテキストが存在しない状態を維持できれば、そういう考え方もありなのかと思ってきました。

---

雑記はここで終わります。