3

I am trying to create a responsive layout using flexbox where one pair of items (two and four) need to be stacked, next to section three when on a large screen, but then on narrow screens, the order needs to change so that they are stacked, one, two, three, four.

I've got a solution, but it isn't DRY, as you can see in the snippet I have duplicated section four.

Is it possible to achieve this using flexbox without the duplication?

.container {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
  border: 1px solid red;
}
.section {
  border: 1px solid green;
  flex-grow: 1;
}
.one, .two, .four {
  width: 100%;
}
.sub-container {
  display: inline-flex;
  flex-direction: column;
  width: 50%;
}
.mobile-only {
  display: none;
}
@media (max-width: 600px) {
  .container {
    flex-direction: column;
  }
  .sub-container {
    width: 100%;
  }
  .section {
    width: 100%;
  }
  .desktop-only {
    display: none;
  }
  .mobile-only {
    display: block;
  }
}
<div class="container">
  <div class="section one">One</div>
  <div class="sub-container">
    <div class="section two">Two</div>
    <div class="section four desktop-only">Four</div>
  </div>
  <div class="section three">Three</div>
  <div class="section four mobile-only">Four</div>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • Yes, if you can wrap two/four and three and set a fixed height on that wrapper...if not, then you need a script, or it might be doable with CSS Grid – Asons Aug 21 '17 at 11:54
  • Well, there is one more way, can three's height be controlled by the sum of two/four, and if the content in three gets bigger it gets a scroll? – Asons Aug 21 '17 at 11:57

1 Answers1

4

Flexbox isn't designed for building 2-dimensional grids (where columns and rows can intersect). So for your layout to work using flex properties, you're going to have to hack your way there.

Here's a more complete explanation of the problem:

However, your layout is simple and easy with CSS Grid.

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 50px;
  grid-gap: 5px;
  grid-template-areas: " one one "
                       " two three "
                       " four three ";
}

.one   { grid-area: one; }
.two   { grid-area: two; }
.three { grid-area: three; }
.four  { grid-area: four; }

@media ( max-width: 600px ) {
  .container {
       grid-template-columns: 1fr;
       grid-template-areas: " one "
                            " two "
                            " three"
                            " four ";
       }
}

/* non-essential; just for demo */
.section {
  border: 1px solid gray;
  background-color: lightgreen;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="container">
  <div class="section one">One</div>
  <div class="section two">Two</div>
  <div class="section three">Three</div>
  <div class="section four">Four</div>
</div>

https://jsfiddle.net/9fyprm3u/

The Grid specification provides multiple methods for designing grids. In this case, I've use the grid-template-areas property which allows you to lay out grid items using ASCII art.

browser support

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    @LGSon: you do; CSS Grids are fantastic to work with! :) As an intro I'd recommend reading Eric Meyer's "A List Apart" article: "[Practical CSS Grid: Adding Grid to an Existing Design](https://alistapart.com/article/practical-grid)." – David Thomas Aug 21 '17 at 14:25
  • @DavidThomas I see what one can do (know some already), but far from all :) ... and thanks for the link – Asons Aug 21 '17 at 14:53