Search code examples
htmlcssflexboxcss-grid

Re-arranging flexbox layout for mobile view


I have 4 divs that I am using flexbox to align. At desktop size, there are 3 equal width columns with the first and last divs taking up the entire height of the container. The second and third divs stack vertically in the middle with each taking up 50% of the height. That's working fine.

At mobile size, I want the last div to be on top and to stretch the entire width of the container. Then I want the first div to align left underneath the top div and take up 50% of the width and the remaining height of the container.

The problem I'm having is I want the second and third div to align right under the top div and take up the remaining 50% of the width but to stack vertically so each takes up 50% of the remaining height.

I've tried changing the flex-direction in the media query and everything else I can think of but it's not working.

* {
  margin: 0;
  padding: 0;
}

.box-wrapper {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 70vh;
  align-items
}

.boxa {
  background: red;
  flex: 0 0 100%;
  width: 33%;
}

.boxb {
  background: orange;
}

.boxc {
  background: lightgreen;
}

.boxb,
.boxc {
  flex: 0 0 50%;
  width: 33%;
}

.boxd {
  background: grey;
  flex: 0 0 100%;
  width: 33%;
}

@media (max-width: 700px) {
  .boxa {
    order: 2;
    width: 50%;
    flex: 0 0 75%;
  }
  .boxb {
    order: 3;
    width: 50%;
    flex: 0 0 37.5%;
  }
  .boxc {
    order: 4;
    width: 50%;
    flex: 0 0 37.5%;
  }
  .boxd {
    order: 1;
    flex: 0 0 25%;
    width: 100%;
  }
}
<div class="box-wrapper">
  <div class="boxa"></div>
  <div class="boxb"></div>
  <div class="boxc"></div>
  <div class="boxd"></div>
</div>


Solution

  • The layout you want is difficult to achieve with flexbox because flexbox is not well-suited for 2-dimensional grids. It excels at 1-dimensional grids (placing flex items in rows or columns), but has limited capacity in 2-dimensional grids (placing flex items in rows and columns).

    Being that your desired layout involves items having to cross row and column lines, flex is not your best option. With CSS Grid, your layout is simple and easy.

    jsFiddle demo

    .box-wrapper {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;  /* 3 equal width columns */
      grid-template-rows: 1fr 1fr;         /* 2 equal height rows */
      height: 70vh;
      grid-column-gap: 5px;
      grid-row-gap: 5px;
      padding: 5px;
      grid-template-areas: " first second last " 
                           " first  third last ";
    }
    
    .boxa { grid-area: first; background: red; }
    .boxb { grid-area: second; background: orange; }
    .boxc { grid-area: third; background: lightgreen; }
    .boxd { grid-area: last; background: grey; }
    
    @media ( max-width: 700px) {
      .box-wrapper {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
        grid-template-areas: "  last   last  "
                             " first  second " 
                             " first   third ";
      }
    }
    
    * { margin: 0; padding: 0; }
    
    /* for placing and styling numbers only */
    .box-wrapper > div {
      font-size: 1.5em; display: flex; align-items: center; justify-content: center; }
    <div class="box-wrapper">
      <div class="boxa">1</div>
      <div class="boxb">2</div>
      <div class="boxc">3</div>
      <div class="boxd">4</div>
    </div>

    More information: