4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CSSAdvent Calendar 2022

Day 8

CSSのGridをカジュアルに使いたい(雑記)

Last updated at Posted at 2022-12-08

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


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

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

ナビゲーションとか

スクリーンショット 2022-12-07 0.08.13.png

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

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

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

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

スクリーンショット 2022-12-07 0.21.03.png

全体として使う

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

スクリーンショット 2022-12-07 0.31.21.png

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

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

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

スクリーンショット 2022-12-07 0.42.27.png

HTML

<div class="container">
  lorem...
  
  <div class="full">
   lorem...
  </div>

  lorem...
</div>

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

HTML

<body>
  <div>
    lorem...
  </div>
  <div class="full">
    lorem...
  </div>
  <div>
    lorem...
  </div>
</body>
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

: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で実装すると簡単! コンテンツは中央配置、最大幅・全幅・ちょい広めのレイアウトを実装できるテンプレート | コリス

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

: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

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

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

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

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

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

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

スクリーンショット 2022-12-07 2.14.21.png

/* 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

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 に依存したレイアウトを強要するツールをいくつか見かけます。プレーンテキストが存在しない状態を維持できれば、そういう考え方もありなのかと思ってきました。


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

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?