こんにちは。今回はタイル状かつタイルのサイズが違う場合のスマートなコーディング方法を解説しようと思います。
例えば次のようなレイアウトです。Airbnbのサイトにあるレイアウトですが、最初の画像だけサイズが違います。
これだけなら左右に要素を分けてdisplay: flex; で横並べにする方法もあります。下記コードのようなイメージです。
<div class="TileArea">
<div class="TileArea__Left">
<img src="path/to/image" class="TileImage" />
</div>
<div class="TileArea__Right">
<img src="path/to/image" class="TileImage" />
<img src="path/to/image" class="TileImage" />
<img src="path/to/image" class="TileImage" />
<img src="path/to/image" class="TileImage" />
</div>
</div>
.TileArea {
display: flex;
}
しかし、
- SP版になった時のレイアウトの関係でflexだと記述が煩雑になる
- アプリケーションのフロントだった場合、ループの関係で出来れば画像の要素は全て並列に並べたい
という問題があったりします。そこでgrid-template-areasというプロパティを使ってそれらを解決しましょう。今回の方法は、PC/SPで多少要素の並び方や順番が変わっても幅広く対応できるのでおすすめです。
本記事のような細かいテクニックをまとめた本を出しておりますので、コーディングスキルを上げたい方はぜひ合わせてご覧ください。
結論
先ほど挙げた例のように、
- 左側に大きいタイルが1つ
- 右側に小さいタイルが4つ
というレイアウトを作ってみましょう。ちなみにSP版(width: 768px以下)では縦1列になるようにします。
destyle.css(https://nicolas-cusan.github.io/destyle.css/)というリセットCSSを使っている前提になりますが、以下のようなコードになります。
CSSの7〜9行目と18〜23行目、grid-template-areasの指定がポイントです。
<ul class="List">
<li class="List-Item GridAreaA">
<div class="Tile">A</div>
</li>
<li class="List-Item GridAreaB">
<div class="Tile">B</div>
</li>
<li class="List-Item GridAreaC">
<div class="Tile">C</div>
</li>
<li class="List-Item GridAreaD">
<div class="Tile">D</div>
</li>
<li class="List-Item GridAreaE">
<div class="Tile">E</div>
</li>
</ul>
.List {
width: 100%;
max-width: 800px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto auto;
grid-template-areas:
'a a b c'
'a a d e';
gap: 8px;
}
@media screen and (max-width: 768px) {
.List {
max-width: 300px;
grid-template-columns: 1fr;
grid-template-rows: auto auto auto auto auto;
grid-template-areas:
'a'
'b'
'c'
'd'
'e';
}
}
.List-Item {
width: 100%;
}
.Tile {
width: 100%;
aspect-ratio: 1/1;
background-color: #ffc0cb;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
}
.GridAreaA {
grid-area: a;
}
.GridAreaB {
grid-area: b;
}
.GridAreaC {
grid-area: c;
}
.GridAreaD {
grid-area: d;
}
.GridAreaE {
grid-area: e;
}
実装すると以下のようになります。横幅を縮めると縦1列になります。
-
A
-
B
-
C
-
D
-
E
解説
コードがやや長くなっていますが、手順をまとめると、
- grid-template-columns, grid-template-rowsで何行何列のグリッドかを定義する。
- grid-template-areasでセルに名前をつける。名前は複数のセルに渡っても良い(これが重要!)。
- 子要素側でgrid-areaを使い、上記で設定した名前を使ってどのセルに当てはまるかを定義する。
- SP版のためにグリッドそのものを組み替える
となっています。順番に細かく見ていきましょう。gridの部分について抜き出して解説します。
grid-template-columns, grid-template-rowsで何行何列のグリッドかを定義する。
これは通常通りのdisplay: grid; の使い方ですね。grid-template-columnsで列を、grid-template-rowsで行を定義します。今回の例では2行4列のグリッドを作ります。
.List {
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto auto;
}
この時点では以下の画像の状態になっているイメージです。
frはグリッド特有の単位で、これを使うと指定されている列が均等に分かれます。
参考:
grid-template-columns – CSS: カスケーディングスタイルシート | MDN
grid-template-rows – CSS: カスケーディングスタイルシート | MDN
grid-template-areasでセルに名前をつける。名前は複数のセルに渡っても良い。
ここが重要です。先ほど作った4列2行のグリッドの各セルに名前をつけます。書き方が見慣れないかと思いますが、実際のグリッドの形に見立てて名前をつけています。
.List {
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto auto;
/* ここから追加 */
grid-template-areas:
/* 1 2 3 4 列目 */
'a a b c' /* 1行目 */
'a a d e' /* 2行目 */;
}
ポイントは「複数のセルをまとめて名付けることで、そのセルが1つのセルとしてみなされること」です。つまり1行目の1〜2列目、2行目の1〜2列目、合わせて4つ分のセルが結合された形になります。以下の状態になっているイメージです。
これで大枠ができました。
参考:grid-template-areas – CSS: カスケーディングスタイルシート | MDN
子要素側でgrid-areaを使い、上記で設定した名前を使ってどのセルに当てはまるかを定義する。
では子要素で「どれがどのエリアに当てはまるか」を定義しましょう。子要素の見た目は共通の場合、grid-areaに関するものだけを分けたクラスを用意しておくと便利です。
<ul class="List">
<li class="List-Item GridAreaA">
<div class="Tile">A</div>
</li>
<li class="List-Item GridAreaB">
<div class="Tile">B</div>
</li>
<li class="List-Item GridAreaC">
<div class="Tile">C</div>
</li>
<li class="List-Item GridAreaD">
<div class="Tile">D</div>
</li>
<li class="List-Item GridAreaE">
<div class="Tile">E</div>
</li>
</ul>
.List-Item {
/* 見た目に関わるものだけなので省略 */
}
.Tile {
/* 見た目に関わるものだけなので省略 */
}
.GridAreaA {
grid-area: a;
}
.GridAreaB {
grid-area: b;
}
.GridAreaC {
grid-area: c;
}
.GridAreaD {
grid-area: d;
}
.GridAreaE {
grid-area: e;
}
「ul、liタグはリストという枠組みを定義しているに過ぎず、中に含まれるものは別途指定したい」という個人的な好みで.List-Itemと.Tileを分けていますが、.Tileの要素は省略して.List-Itemに見た目を指定しても構いません。
こうすると、子要素がそれぞれのエリアに当てはめられます(下画像)。実際にはデザインに合わせて子要素の見た目、余白などを調整してください。
参考:grid-area – CSS: カスケーディングスタイルシート | MDN
SP版のためにグリッドそのものを組み替える
さて、SP版では縦1列になると仮定します。その場合どうすれば良いでしょうか。その場合はグリッドの形を組み替えて対応しましょう。具体的には、
- 1列5行のグリッドにする。
- エリア名は上からa, b, c, d, eにする
という記述を行う必要があります。グリッドの形状と各セルのエリア名を再定義するわけですね。コードは以下の通り。
@media screen and (max-width: 768px) {
.List {
grid-template-columns: 1fr; /* 1列 */
grid-template-rows: auto auto auto auto auto; /* 5行 */
grid-template-areas:
/* 1 列 */
'a' /* 1行目 */
'b' /* 2行目 */
'c' /* 3行目 */
'd' /* 4行目 */
'e' /* 5行目 */;
}
}
こうすることで、子要素は単純に縦に並びます。
これでタイルの配置がうまく行きました。
応用
グリッドの形状、エリアの定義方法を見ていただくとわかると思うのですが、かなり自由に組み替えが可能です。順番も必ずしもPC/SPで一致していなくても構いません。
具体的には過去に書いた記事で応用例を解説していますので合わせてご覧ください。
まとめ
というわけでgrid-template-areasを使った特殊なレイアウトの解説でした。かなり多くの場面で使える汎用的な方法なのでぜひお試しください。
今回ような細かいテクニックをまとめた本を出しておりますので、コーディングスキルを上げたい方はぜひ合わせてご覧ください。
コメント