思ったままに記述と検証を繰り返した記事です。
CSSのGridといえば、縦軸と横軸を決め、それあわせてボックスを配置できる技術です。grid-template-rows / columns
や grid-template-areas
を使って、ごにょごにょします。
しかしこれらを使用する場合は、限定的なレイアウトをしっかり組みたい時に利用する場合が多いと思います。
もっとカジュアルにGridが使いたいので、少し考えてみました。
ナビゲーションとか
ナビゲーションの子同士でスペースが必要な場合があります。
今までなら「:first-child を使った marginの打ち消し」や「隣接セレクタ」でmarginを取っていました。
Gridとgapを使えば、簡単に子同士のスペースは簡単に開きます。
display: grid;
と指定すれば一見通常フローの並びになりますが、子はGridコンテナになるので楽に指定できます。
ul {
display: grid;
gap: 16px;
}
もちろん Grid は、論理プロパティに対応しているので、幅も inline-size
にしておけば、 writing-mode: vertical-rl;
が必要になっても綺麗に並んでくれます。
全体として使う
Gridは、左にナビゲーションがあって、右がコンテンツで〜〜〜といった少し凝ったレイアウトに使うというイメージがありました。
ただよくよく考えると、もっと柔軟に考えてもいい気がしてきました。
上記は見た目は簡素ですが、よくあるサイトを囲ったりするコンテナです。
下記は、その宣言ブロックのCSSです。
.container {
max-width: 800px;
margin: auto;
border: 1px solid #000;
}
よく使われている margin で中央に寄せる方法の弱点としては、広がったコンテンツの対応が少し気持ち悪いです。
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 をそのまま適用します。
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 を調整します。
: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コンテナは、要素ではないので理想とする配置にはなりません。
body要素だから、プレーンテキストをそのまま配置するというこはあまりしませんが、この手法を子要素で行なった時に、意図しないレイアウトになりそうです。
汎用性や条件などを考えると、Grid をカジュアルに使ってる感じはしません。
max-width & margin: auto
の方がわかりやすいですね。
ただ、こういう手法も引き出しに入れておくだけで、レイアウトの表現方法に幅が出そうです。
Grid は関係ないけど、思いついた
画面いっぱいの広がる下記の宣言ブロックですが、 viewport を基準にするから、横スクロールが出る。
/* いつもの */
.full {
margin-inline: calc(50% - 50vw);
padding-inline: calc(50vw - 50%);
}
なら Container Queries を使えばいい気がしてきました。
/* 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
が上書きされてしまいます。
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 に依存したレイアウトを強要するツールをいくつか見かけます。プレーンテキストが存在しない状態を維持できれば、そういう考え方もありなのかと思ってきました。
雑記はここで終わります。