1

I am trying to create a flexbox container that contains a list of items in a row format and then each of those items will be a flexbox with items in a wrapping column format. However, it seems that the first containers rows do not expand to fit the contents of the wrapping columns and end up overlapping each other.

enter image description here

Demo

I want the end result to look like this: enter image description here

.flex-group {
  display: flex;
}

.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  border: 1px solid silver;
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 500px;
}

.red li {
  background: red;
}

.gold li {
  background: gold;
}

.blue li {
  background: deepskyblue;
}

.flex-item {
  padding: 5px;
  width: 100px;
  height: 100px;
  margin: 10px;
  
  line-height: 100px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
}
<div class="flex-group">

  <ul class="flex-container blue">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
    <li class="flex-item">5</li>
    <li class="flex-item">6</li>
    <li class="flex-item">7</li>
    <li class="flex-item">8</li>
  </ul>
  <ul class="flex-container red">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
  </ul>

  <ul class="flex-container gold">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
    <li class="flex-item">5</li>
  </ul>

<div>

So at the end of the day, I'm looking to have a non-wrapping row where each of the child elements (dynamic amount) can contain a set of column wrapping elements (dynamic amount). Note: You can almost get the solution if you make the .flex-container have flex-direction: row but I need flex-direction: column since order does matter in this scenario. The main container needs to have a fixed height and each child container can have a dynamic width (due to wrapping elements causing them to grow horizontally).

TylerH
  • 20,799
  • 66
  • 75
  • 101
Dustin
  • 455
  • 1
  • 6
  • 17
  • Would adding a `flex-grow: 1;` to your `flex-container` do it for you? – Prosy Arceno May 12 '21 at 16:58
  • @ProsyArceno `flex-grow: 1;` would only distribute the space evenly amongst the other containers as well and would still result in overlapping elements. Considering that the number of elements in each container is dynamic, this could still lead to overlap. – Dustin May 12 '21 at 17:15
  • Why are you setting a fixed height to ```.flex-container```? – prettyInPink May 12 '21 at 17:20
  • @prettyInPink This is going to simulate a menu that has a fixed height, hence the column wrapping. Just one of the requirements I have. – Dustin May 12 '21 at 17:22
  • Can you just create a mockup of what you want, it'll probably make things a lot easier ;) – prettyInPink May 12 '21 at 17:28
  • @prettyInPink Updated w/ example of end goal :) – Dustin May 12 '21 at 17:36
  • is there a particular reason why you did not specify width for each colour block? – Huangism May 12 '21 at 17:44
  • @Huangism The width of each colored block is specified within the `flex-item` class as `width: 100px;` – Dustin May 12 '21 at 17:47
  • @Dustin I mean for the flex-container – Huangism May 12 '21 at 17:52
  • @Huangism So the flex-container itself can grow from the wrapping elements (see example above). This is due to the dynamic content in the container. – Dustin May 12 '21 at 17:54
  • @Dustin well it looks like flex-container is treating the wrapping boxes as overflow so the width does not expand – Huangism May 12 '21 at 17:58

3 Answers3

0

If you will use grid, you can use this:

.flex-group {
  display: flex;
}

.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  border: 1px solid silver;
  display: grid;
  grid-template-rows: repeat(3, auto);
  gap: 10px;
  grid-auto-flow: column;
  height: 500px;
}

.red li {
  background: red;
}

.gold li {
  background: gold;
}

.blue li {
  background: deepskyblue;
}

.flex-item {
  padding: 5px;
  width: 100px;
  height: 100px;
  margin: 10px;
  line-height: 100px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
}
<div class="flex-group">

  <ul class="flex-container blue">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
    <li class="flex-item">5</li>
    <li class="flex-item">6</li>
    <li class="flex-item">7</li>
    <li class="flex-item">8</li>
  </ul>
  <ul class="flex-container red">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
  </ul>

  <ul class="flex-container gold">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
    <li class="flex-item">5</li>
  </ul>

  <div>
Prosy Arceno
  • 2,616
  • 1
  • 8
  • 32
  • So in my example, I show that each flex-item was the same height. What about the scenario where the heights are different? I see that you used `grid-template-rows: repeat(3, auto);`. Is there some value we can use instead where the height is dynamic for these items as well? I mistakenly added a height just for a visual reference. This height will be dynamic as well. – Dustin May 12 '21 at 18:33
  • I don't know anymore. You could do javaScript as suggested by the other answer. – Prosy Arceno May 12 '21 at 18:48
0

There are a lot of similar question but no answers. I think a workaround can satisfy your needs. Include a script to calculate the width depending on the height you assign to each flex-container and the flex-item height:

check it out here

enter image description here

I had to fix the height to 400px to get the same output as yours but this script will calculate number of cols and lines needed. Couldn't get the padding properly though so I set a variable that will get me the desired output

document.querySelectorAll('.flex-container').forEach((e)=>{

  let p = 10 ;
  let childCount = e.childElementCount;
  let childHeight = e.children[0].clientHeight ; 
  let childWidth = e.children[0].clientWidth ; 
  let lines = Math.round((e.clientHeight / (e.children[0].clientHeight + 2*p))) ;
  let cols = Math.round(childCount / lines) ;
  let width = cols * ( 2*p +  childWidth );
 
  e.style.width = width+"px";
  
});

Still if you want a column based display for your items similar to Pinterest then you need to specify in advance the number of columns and use Masonry Layout :


.masonry-container {
 column-count: 3;
 column-gap: 15px;
}
.masonry-item {
 display: inline-block;
 width: 100%;
}

Andrew
  • 307
  • 7
  • 13
HijenHEK
  • 1,256
  • 1
  • 4
  • 13
-1

I'm not sure I got this, but it sounds like you don't want your columns to be in 'wrap' mode. You may try to change those values:

.flex-container {
/* leave the rest of what was here*/
  flex-wrap: nowrap;
  height: 100%;
}

This is what I thought you want to achieve: expected solution

Santiago V.
  • 1,088
  • 8
  • 24
  • So I will still need the wrapping since the height of the container is fixed. I'm not sure if flexbox is the way to go or maybe grid instead? – Dustin May 12 '21 at 17:29