grid-template-columns: 1fr
の指定により、列は「残りのスペースを取る」という意図になります。 しかし、1fr
は単に「余白だけ」を使うのではなく、子要素のmin-contentサイズを尊重するという挙動をとります。
つまり、1fr
は実際にはminmax(auto, 1fr)
に近い動作をします。 子要素の幅が極端に広い場合(たとえば横スクロール可能なカルーセルなど)、その最小幅をもとに列幅が決まり、結果的に親要素をオーバーフローしてしまいます。
これを防ぐには、明示的にminmax(0, 1fr)
と指定する必要があります。最小幅を0
に制限し、親要素内に収まるように制御することが可能です。 TailwindCSSでも、グリッドアイテムのオーバーフローを防ぐために、グリッドのトラックサイズにはminmax(0, 1fr)
が採用されています。
1fr
を使用する際には明示的に最小値を指定した方が無難なようです。
gird-template-column
等で使用するfr
は簡約化した数値でなくても動作します。そのためデザインカンプに記載されている数値をそのままfrに当てはめると、その比率を保ったまま拡大・縮小してくれます。
/* 最大公約数で簡約化した例 */.col { gird-template-column: 5fr 3fr;}
/* デザインカンプの値をそのまま反映した例 */.col { gird-template-column: 420fr 252fr;}
以前はなぜか最大公約数で簡約化した数値を記述する必要があると思い込んでいたため、比率計算機などでわざわざ計算を行った上で入力していました。
ただ実際には簡約化した数値でなくても動くので、そのままの値を当てはめるようにしています。
grid-template
を使用することで以下のプロパティを一括で指定することができます。
よくあるカードのコンポーネントで、一括指定を行わなかった場合は以下のようになります。
.card { display: grid; grid-template-areas: 'img title' 'img text' 'img button' ; grid-template-columns: 3fr 2fr; grid-template-rows: auto auto 1fr;}
これをgrid-template
で一括して書くと次のようになります。
.card { display: grid; grid-template: 'img title' auto 'img text' auto 'img button' 1fr / 3fr 2fr;}
かなりスッキリしましたよね。
エリアの記述の下側と右側にそれぞれのトラックサイズを書くので、別々に書いた時よりもトラックサイズが読み取りやすく感じます。gridでエリアを定義する際にはgrid-template
の一括指定を積極的に使用するようにしています。
display: gird;
を使用する際にはgrid-template-areas
を使用してエリアを定義する方法としない方法の2種類の記述パターンがあります。この違いについて見ていきます。
以下は各セルのエリアを定義した例です。
.card { display: grid; grid-template: 'img title' auto 'img text' auto 'img button' 1fr / 3fr 2fr;}
.img { grid-area: img;}
.title { grid-area: title;}
.text { grid-area: text;}
.button { grid-area: button;}
一方で下記は各セルのエリアを定義しない例です。grid-column
とgrid-row
を使って各アイテムの割り当てられるトラックを指定しています。
.card { display: grid; grid-template-columns: 3fr 2fr; grid-template-rows: auto auto 1fr;}
.img { grid-column: 1 / 2; grid-row: 1 / 4;}
.title { grid-column: 2 / 3; grid-row: 1 / 2;}
.text { grid-column: 2 / 3; grid-row: 2 / 3;}
.button { grid-column: 2 / 3; grid-row: 3 / 4;}
直感的に見て理解しやすいのは「エリアを定義した例」かなと感じます。エリアを定義した場合のメリットとデメリットについて考えてみました。
メリット | デメリット |
---|---|
|
|
エリアの定義はシンプルなレイアウトでは過剰になってしまいますが、複雑なレイアウトではメリットが多いと感じます。私の場合、次のような使い分けをしています。
columns/rows
またはorder
で対応)要素の自動配置のみでレイアウトの大部分を組める場合は、エリアを定義しないことが多いです。
ただ実際にはその他にも、レスポンシブでレイアウトが変わるかや、将来変更の可能性があるのかなども考慮し総合的に判断しています。
グリッドアイテムの間の余白を設定するには以下のようにgap
を使用することが多いと思います。
.card { display: grid; grid-template: 'img title' auto 'img text' auto 'img button' 1fr / 3fr 2fr; row-gap: 20px; column-gap: 40px;}
よくあるのが1〜2行目の間の余白と、2〜3行目の間の余白を異なる値で設定したいというパターンです。
この場合row-gap
を指定したままグリッドアイテム側で余白を調整する方法も良いですが、以下のようにtemplateの中でピリオドを使用することで個別に余白を設定することもできます。
.card { display: grid; grid-template: 'img title' auto '. .' 20px 'img text' auto '. .' 30px 'img button' 1fr / 3fr 2fr; column-gap: 40px;}
余白の値が共通の場合にはrow-gap
またはcolumn-gap
を、余白の値が異なる場合にはピリオドを使うと良いかもしれません。
今回紹介したレイアウトの大部分はdisplay: flex;
などの他のプロパティでも代用可能です。ただレイアウトの再現方法については選択肢が多いに越したことはないと考えています。
複数ある選択肢の中からそのデザインに最適なプロパティを選び実装することが、コーダーの仕事の醍醐味のような気がします(この辺りが難しくもあり楽しくもあるコーダーの役割だと感じています)。
特定のプロパティに依存せず様々なレイアウトを表現できるよう日々勉強です。