Search code examples
htmlcssflexboxcss-grid

Wrap multiple small items next to one large item


The goal I'm trying to archive is the following:

Wrapping multiple items

I would like to wrap multiple items around one large item. If possible, I would like to avoid nesting the items into another div, because then I might loose the easy opportunity to re-order items.

One item will always be at the most left/top position. This item might dynamically change, with the class item-active. So, ordering of the items is something that I would like to take into account. That got me to choose Flexbox. CSS-Grid might also be attempting as a solution, but I'm a little concerned about browser support.

I tried to fiddle around a bit, but couldn't come up with a satisfying solution:

.flex-container {
  display: flex;
  position: relative;
  align-items: flex-end;
  flex-flow: row wrap;
}

.item {
  box-sizing: border-box;
  border: 1px solid black;
  color: #fff;
  display: block;
  text-align: center;
  line-height: 200px;
  font-size: 3rem;  
  
  width: 25%;
}

.item-active { order: 1; position: absolute; top: 0; left: 0; }

.item-1 { background: #3CFF8A }
.item-2 { background: #3CFFC0 }
.item-3 { background: #3CFFF4 }
.item-4 { background: #3CD4FF }
.item-5 { background: #3C9FFF }
.item-6 { background: #3C6EFF }
.item-7 { background: #3C56FF }
.item-8 { background: #583CFF }
.item-9 { background: #8D3CFF }
<div class="flex-container">
  <div class="item item-1">1</div>
  <div class="item item-2 item-active">2<br><br></div>
  <div class="item item-3">3</div>
  <div class="item item-4">4</div>
  <div class="item item-5">5</div>
  <div class="item item-6">6</div>
  <div class="item item-7">7</div>
  <div class="item item-8">8</div>
  <div class="item item-9">9</div>
</div>

I thought using flex-wrap + flex-direction with a item positioned absolute could solve it. Unfortunately not.

  • What is missing to archive it?
  • Would it even be possible to archive it with flexbox?
  • Flexbox is one-dimensional. Does my requirement already count as two-dimensional?

Solution

  • This can easily be done using CSS grid which is more suitable than flexbox since what you have is a two-dimensional grid.

    .flex-container {
      display: grid;
      grid-template-columns:repeat(6,1fr);
      grid-template-rows:repeat(3,50px);
      grid-gap:5px;
      margin:5px;
    }
    
    .item {
      box-sizing: border-box;
      border: 1px solid black;
      color: #fff;
      text-align: center;
      font-size: 3rem;  
    }
    
    .item-active {
       grid-column:1/span 3;
       grid-row:1/span 3;
    }
    
    .item-1 { background: #3CFF8A }
    .item-2 { background: #3CFFC0 }
    .item-3 { background: #3CFFF4 }
    .item-4 { background: #3CD4FF }
    .item-5 { background: #3C9FFF }
    .item-6 { background: #3C6EFF }
    .item-7 { background: #3C56FF }
    .item-8 { background: #583CFF }
    .item-9 { background: #8D3CFF }
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2 item-active">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9">9</div>
    </div>
    
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2 ">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5 item-active">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9">9</div>
    </div>
    
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9 item-active">9</div>
    </div>

    Using flexbox it can be done with some hacks

    .flex-container {
      display: flex;
      flex-wrap:wrap;
    }
    
    .item {
      box-sizing: border-box;
      border: 1px solid black;
      color: #fff;
      text-align: center;
      font-size: 3rem;  
      height:50px;
      width:calc(100%/6 - 10px);
      margin:5px;
    }
    
    .item-active {
      order:-1;
      width:calc(100%/2 - 10px);
      height:calc(150px + 20px);
      margin-bottom:calc(-100px - 20px);
    }
    
    .item-active:nth-child(-n + 4) ~ :nth-child(5),
    .item-active:nth-child(-n + 7) ~ :nth-child(8){
      margin-left:calc(100%/2 + 5px)
    }
    
    .item:nth-child(4),
    .item:nth-child(7){
      margin-left:calc(100%/2 + 5px)
    }
    .item-active:nth-child(-n + 4) ~ :nth-child(4),
    .item-active:nth-child(-n + 7) ~ :nth-child(7){
     margin-left:5px;
    }
    
    
    .item-1 { background: #3CFF8A }
    .item-2 { background: #3CFFC0 }
    .item-3 { background: #3CFFF4 }
    .item-4 { background: #3CD4FF }
    .item-5 { background: #3C9FFF;}
    .item-6 { background: #3C6EFF }
    .item-7 { background: #3C56FF }
    .item-8 { background: #583CFF;}
    .item-9 { background: #8D3CFF }
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2 item-active">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9">9</div>
    </div>
    
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2 ">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5 item-active">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9">9</div>
    </div>
    
    <div class="flex-container">
      <div class="item item-1">1</div>
      <div class="item item-2">2<br><br></div>
      <div class="item item-3">3</div>
      <div class="item item-4">4</div>
      <div class="item item-5">5</div>
      <div class="item item-6">6</div>
      <div class="item item-7">7</div>
      <div class="item item-8">8</div>
      <div class="item item-9  item-active">9</div>
    </div>