0

I'm trying to arrange "items" (child divs) in "containers" (parent divs) in a way that

  • items wrap within flexible-width containers, so that containers are as narrow as possible, but in max. two rows
  • containers wrap within the page (or within some wrapper/containercontainer).

This is what I want:

┌───┐┌─────────┐┌─────┐
│ █ ││ █ █ █ █ ││ █ █ │
│ █ ││ █ █ █   ││ █ █ │
└───┘└─────────┘└─────┘

Kind of the opposite of this, where the number of items per row is fixed, but the number of rows is flexible.
My attempt was to make containers and their parent display:flex, to give the containers a fixed height that allows only two rows, and to give the containers a high flex-shrink value, so they would try to be as narrow as possible and make their child items wrap. But items don't wrap this way, instead, I get this

.wrapper {
  display:flex;
  flex-wrap:wrap;
  font-size:2vw;
  width:96vw;
}
.container {
  flex:0 20 auto;
  display:flex;
  flex-wrap:wrap;
  height:20vw; 
  margin:1vw;
  background:skyblue;
}
.item {
  position:relative; 
  width:10vw;
  height:7vw;
  margin:1vw;
  background:orange;
}
<div class="wrapper">
  <div class="container">
    <div class="item">1a</div>
    <div class="item">1b</div>
  </div>
  <div class="container">
    <div class="item">2a</div>
    <div class="item">2b</div>
    <div class="item">2c</div>
    <div class="item">2d</div>
    <div class="item">2e</div>
    <div class="item">2f</div>
    <div class="item">2g</div>
  </div>
  <div class="container">
    <div class="item">3a</div>
    <div class="item">3b</div>
    <div class="item">3c</div>
    <div class="item">3d</div>
  </div>
</div>
┌─────┐
│ █ █ │
│     │
└─────┘
┌───────────────┐
│ █ █ █ █ █ █ █ │
│               │
└───────────────┘
┌─────────┐
│ █ █ █ █ │
│         │
└─────────┘

Items don't feel any urge to wrap, instead they stretch the containers so that they get too wide to wrap, mostly occupy a full row.
Yes, I could brute-force two rows with the help of the backend, but that doesn't feel right :o[.
(Conditions: Height and width of items are defined. Number of items per container is variable, but limited so that each container will fit on the page.)

Any good ideas? Much appreciated! Thanks.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Jan Mirus
  • 263
  • 2
  • 9
  • 1
    Not really possible as such. It is possible to limit to two rows if the height is known by using flex columns -https://codepen.io/Paulie-D/pen/QWKmrOB but this may not be what you are looking for. Note that in order to wrap, the container must have known width/height so that it knows **when** to wrap. – Paulie_D Jan 03 '21 at 18:17

2 Answers2

1

As you said, you will need some backend help here. If you are able to add to each container the number of elements then you can do it like below:

.wrapper {
  display:flex;
  flex-wrap:wrap;
  font-size:2vw;
  width:96vw;
}
.container {
  flex-basis:calc(12vw*var(--n)/2); /* 12 = width + 2*margin */
  min-width:0;
  display:flex;
  flex-wrap:wrap;
  height:20vw; 
  margin:1vw;
  background:skyblue;
}
.item {
  position:relative; 
  width:10vw;
  height:7vw;
  margin:1vw;
  background:orange;
}
<div class="wrapper">
  <div class="container" style="--n:2">
    <div class="item">1a</div>
    <div class="item">1b</div>
  </div> 
  <div class="container"  style="--n:8"> <!-- we round to the biggest even number --> 
    <div class="item">2a</div>
    <div class="item">2b</div>
    <div class="item">2c</div>
    <div class="item">2d</div>
    <div class="item">2e</div>
    <div class="item">2f</div>
    <div class="item">2g</div>
  </div>
  <div class="container"  style="--n:4">
    <div class="item">3a</div>
    <div class="item">3b</div>
    <div class="item">3c</div>
    <div class="item">3d</div>
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Thanks, Temani! Couldn't find no pure css solution either. Love your solution with in-line css constants, rather than in-line flex-basis. Very elegant. – Jan Mirus Jan 04 '21 at 09:22
0

max. two rows

If you need to control the height of the column, you can give the Flex Parent an explicit height (which accommodates the combined height of two Flex Children) and use:

flex-direction: column;

Once two Flex Children have filled the available height (ie. two rows), the wrap will take effect and the next Flex Child will start at the top of the next column.

Rounin
  • 27,134
  • 9
  • 83
  • 108
  • Hi Rounin, thank you! When I try this, the items don't expand their container width. [See pen.](https://codepen.io/MirusVirus/pen/vYXRpPe) Setting container flex-basis to auto doesn't help. What am I doing wrong? – Jan Mirus Jan 03 '21 at 20:47