以下のレイアウトをレスポンシブでスマートに表現する。(HTML/CSSでのみ)
要件
PCは横一列、スマホは1列目にitem1とitem4、2列目にitem2とitem3を隙間を埋めるかたちで並べる。
item2とitem4の中身は動的になるため、各要素の高さの指定は不可。
基本の形のHTML
<div class="wrap">
<div class="item1">
item1<br>
item1<br>
item1<br>
item1
</div>
<div class="item2">
item2<br>
item2<br>
item2<br>
item2<br>
item2
</div>
<div class="item3">
item3<br>
item3
</div>
<div class="item4">
item4<br>
item4<br>
item4
</div>
</div>
その1
display: grid;で再現する
.wrap {
display: grid;
align-items: start;
grid-template-areas: "areaA areaB areaC areaD";
}
.item1 {
grid-area: areaA;
}
.item2 {
grid-area: areaB;
}
.item3 {
grid-area: areaC;
}
.item3 {
grid-area: areaD;
}
@media (max-width: 480px) {
.wrap {
grid-template-areas:
"areaA areaB"
"areaD areaB"
"areaD areaC";
}
}
問題点
item4の要素 >= item2の要素になると item2 の下部に余白が発生してしまう。
item2 が動的なので item3 にposition:absolute; + マイナスマージンで調整も不可。
その2
HTMLをSPベースで作成してcolumn-count: 2;で再現する。
<div class="wrap">
<div class="item1">
item1<br>
item1<br>
item1<br>
item1
</div>
<div class="item4">
item4<br>
item4<br>
item4
</div>
<div class="item2">
item2<br>
item2<br>
item2<br>
item2<br>
item2
</div>
<div class="item3">
item3<br>
item3
</div>
</div>
.wrap {
column-count: 2;
break-inside: avoid;
}
@media (min-width: 480px) {
.wrap {
display: flex;
align-items: flex-start
}
.item2 {
order: 2;
}
.item3 {
order: 3;
}
.item3 {
order: 4;
}
}
問題点
結果
今回の対象は item2 の要素が item1 の要素より少なくなる想定はかったためその2を採用。
その2は自分以外の人が提案したもの。
item1,2,3,4 の順でどうするかしか考えられていなかったので、HTMLを入れ替えて縦でレイアウトを考えるという思考がなるほど…!と思った。
もっと頭柔らかく考えられるようにならなければ…
また、gridの場合で余白を item2 で埋めることはできそうだけど、item3を詰めるのはできないんだろうか…?
最後に
こういう風にすればもっと簡潔に直感的に書けるよ!などあれば教えてください。
追記
itemの入れ替え+itemを2つずつ囲うことを許容してくれる要件ならば編
コメントでご教示いただいたものです。ありがとうございました。
<div class="wrap">
<div class="inner">
<div class="item1">
item1<br>
item1<br>
item1<br>
item1
</div>
<div class="item4">
item4<br>
item4<br>
item4
</div>
</div>
<div class="inner">
<div class="item2">
item2<br>
item2<br>
item2<br>
item2<br>
item2
</div>
<div class="item3">
item3<br>
item3
</div>
</div>
</div>
.wrap {
display: grid;
grid: auto-flow / auto auto;
}
@media (min-width: 480px) {
.wrap {
grid: auto-flow / auto auto auto auto;
align-items: start;
}
.inner {
display: contents;
}
.item {
order: 1;
}
.item2 {
order: 2;
}
.item3 {
order: 3;
}
.item3 {
order: 4;
}
}
HTMLはスマホ起点に要素を 1,4,2,3 の順で並べて 1,4 2,3 ずつinnerで囲う。
PCの表示の場合、要素を囲うinnerをdisplay: contents;
でボックスの生成を制御する。
display: contents;
指定した要素のボックスを生成を制御する。
今回の場合だとPCの場合は
<div class="wrap">
<div class="item1"></div>
<div class="item4"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
と同様になる。
display: none;
と違って指定された要素の中身には影響しない。
主要ブラウザがオールグリーンで対応していないので、テーブルタグ、ボタンに使用するとうまく動かない事に注意。
この方法だとdisplay: flex;
でも対応可能。
https://caniuse.com/?search=CSS%20display%3Acontents%3B
https://blog.to-ko-s.com/css-display-contents/
https://retval.jp/blog/css-display-contents/