Search code examples
cssflexboxgrid-layoutcss-grid

How can I make a div span multiple rows and columns in a grid?


Building off of a previous question, I'm trying to add bigger blocks to my grid layout. In the last question, I needed to have a div span multiple rows. The problem now is that I need a div to span multiple rows and columns.

If I have a five-element row, how could I put bigger elements in the middle of it? (as float puts it naturally on the side).

Here's an example snippet:

#wrapper{
  width: 516px;
}
.block{
  display: inline-block;
  width: 90px;
  height: 50px;
  margin: 5px;
  background-color: red;
}
.bigger{
  height: 110px;
}
.larger{
  height: 110px;
  width: 190px;
}
<div id="wrapper">
  <div class="block"></div>
  <div class="block bigger"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block larger"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
</div>

I don't want to use display: grid for the wrapper element, as Can I Use states this is a pretty on-the-edge technology right now. I was hoping for a non-grid, non-table solution.

Here's what I would like to have from the snippet above Expected


Solution

  • Keeping your HTML as-is, the layout is not natively possible with flexbox. This is primarily because of the 2 x 2 box occupying the third and fourth columns. The closest you can get is this:

    #wrapper{
      display: flex;
      flex-direction: column;
      flex-wrap: wrap;
      align-content: flex-start;
      height: 180px;
      width: 516px;
    }
    .block {
      width: 90px;
      flex: 0 0 50px;
      margin: 5px;
      background-color: red;
    }
    .bigger{
      flex-basis: 110px;
    }
    <div id="wrapper">
      <div class="block"></div>
      <div class="block"></div>
      <div class="block"></div>
      <div class="block bigger"></div>
      <div class="block"></div>
      <div class="block"></div>
      <div class="block bigger"></div>
      <div class="block"></div>
      <div class="block bigger"></div>
      <div class="block"></div>
      <div class="block"></div>
      <div class="block"></div>
    </div>

    As you can see, the big box is broken up between columns.

    As mentioned in the other post you referenced, since you have fixed heights on your child elements (.block), we can determine the height of the container (.wrapper).

    By knowing the height of the container, the layout above can be achieved using flex-direction: column and flex-wrap: wrap.

    A fixed height on the container serves as a breakpoint, telling flex items where to wrap.

    Alternatively, if you can add containers, then the layout is easy. Just create four nested flex containers to hold columns 1, 2, 3-4 and 5, and you're done.

    #wrapper {
      display: flex;
      width: 516px;
    }
    
    section {
      display: flex;
      flex-direction: column;
    }
    
    .block {
      width: 90px;
      height: 50px;
      margin: 5px;
      background-color: red;
    }
    
    .bigger {
      flex-basis: 110px;
    }
    
    section:nth-child(3) {
      flex-direction: row;
      flex-wrap: wrap;
      flex: 0 0 200px;
    }
    
    section:nth-child(3)>.block:last-child {
      flex: 0 0 190px;
      height: 110px;
    }
    <div id="wrapper">
      <section>
        <div class="block"></div>
        <div class="block"></div>
        <div class="block"></div>
      </section>
      <section>
        <div class="block bigger"></div>
        <div class="block"></div>
      </section>
      <section>
        <div class="block"></div>
        <div class="block"></div>
        <div class="block"></div>
      </section>
      <section>
        <div class="block"></div>
        <div class="block"></div>
        <div class="block"></div>
      </section>
    </div>

    Otherwise, see this post for more details and other options: