0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【CSS】高さの異なる横並びの要素をスマホで表示する場合、縦二列にする方法

Last updated at Posted at 2024-07-05

以下のレイアウトをレスポンシブでスマートに表現する。(HTML/CSSでのみ)
image.png

要件

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 の下部に余白が発生してしまう。
image.png
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;
  }
}

問題点

item1 の高さが item2 の高さになると崩れる。
image.png

結果

今回の対象は 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/

0
0
6

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?