13

On large screens, I'd like to have a column on the left, and another column on the right that has 2 stacked boxes.

On small screens, these columns should stack into a single column. However, the order of the boxes should be 2,1,3.

Here is an illustration:

Large Layout

Small Layout

I've set the flex container with flex-direction: column and flex-wrap: wrap, and box 1 to flex-basis: 100%, but that doesn't make the second two items wrap to the next column.

How can this layout be achieved in flexbox?

Here is a demo of where I'm at so far:

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
.cell {
  background: #ccc;
  border: solid 3px black;
  width: 50%;
}
.cell-1 {
  flex-basis: 100%;
}
@media (max-width: 500px) {
  .cell {
    width: 100%;
  }
  .cell-1 {
    order: 2;
  }
  .cell-2 {
    order: 1;
  }
  .cell-3 {
    order: 3;
  }
}
<h1>Vertical Boxes</h1>
<p>Goal: Have one box on the left, and two boxes on the right that are stacked. All without nesting, so that the order of the boxes can be changed on smaller screen sizes.</p>
<div class="container">
  <div class="cell cell-1">
    <h2>One</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit
    amet, consectetur adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit amet, consectetur
    adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure.
  </div>
  <div class="cell cell-2">
    <h2>Two</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste mollitia temporibus id sint illum doloremque pariatur nulla vel soluta, nostrum vitae, suscipit ea natus sed eaque in velit deserunt deleniti!
  </div>
  <div class="cell cell-3">
    <h2>Three</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit, architecto perferendis voluptatum accusantium est ipsam fugit, laudantium fugiat nostrum consectetur earum. Asperiores, similique deleniti nobis nemo error, iste iure architecto.
  </div>
</div>

http://codepen.io/dloewen/pen/qOzogG

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
dloewen
  • 975
  • 1
  • 10
  • 26
  • 2
    There is an absolute saint by the name of philip walton who has proposed solutions to a whole bunch of classic design challenges that are massively simplified by flexbox https://philipwalton.github.io/solved-by-flexbox/demos/grids/ – Simon Merrick Nov 26 '15 at 22:40

2 Answers2

11

It looks like you were almost there. Just two more steps:

  1. Define a height for the flex container

Without a defined height some browsers may not know where to wrap. Try this:

.container {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    height: 500px; /* new; value just for demo purposes */
}
  1. Turn off wrap on mobile view
@media (max-width: 500px) {
   .container { flex-wrap: nowrap; } /* new */
   .cell { width: 100%; }
   .cell-1 { order: 2; }
   .cell-2 { order: 1; }
   .cell-3 { order: 3; }
}

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 500px;
}
.cell {
  background: #ccc;
  border: solid 3px black;
  width: 50%;
}
.cell-1 {
  flex-basis: 100%;
}
@media (max-width: 500px) {
  .container {
    flex-wrap: nowrap;
  }
  .cell {
    width: 100%;
  }
  .cell-1 {
    order: 2;
  }
  .cell-2 {
    order: 1;
  }
  .cell-3 {
    order: 3;
  }
}
<h1>Vertical Boxes</h1>
<p>Goal: Have one box on the left, and two boxes on the right that are stacked. All without nesting, so that the order of the boxes can be changed on smaller screen sizes.</p>
<div class="container">
  <div class="cell cell-1">
    <h2>One</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit
    amet, consectetur adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit amet, consectetur
    adipisicing elit. Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure. Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    Iusto pariatur rerum, illum accusantium cupiditate ipsam, eaque quae fugit cum assumenda ad. Modi, excepturi. Assumenda, nobis, consequatur? Aliquid repellendus quis, iure.
  </div>
  <div class="cell cell-2">
    <h2>Two</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste mollitia temporibus id sint illum doloremque pariatur nulla vel soluta, nostrum vitae, suscipit ea natus sed eaque in velit deserunt deleniti!
  </div>
  <div class="cell cell-3">
    <h2>Three</h2>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit, architecto perferendis voluptatum accusantium est ipsam fugit, laudantium fugiat nostrum consectetur earum. Asperiores, similique deleniti nobis nemo error, iste iure architecto.
  </div>
</div>

revised codepen

MauriceNino
  • 6,214
  • 1
  • 23
  • 60
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Ah, makes sense. The only problem is the left column could have any height, so I'll have to calculate and force its height with JavaScript. – dloewen Nov 27 '15 at 19:24
  • 1
    How would this work without the `height: 500px;`? Removing this seems to kill the layout. – Andrew Feb 03 '17 at 01:22
  • @Andrew, if you don't give the container a fixed height, how will the items know where to wrap? They will just keep expanding the container in a single column. – Michael Benjamin Feb 03 '17 at 02:26
  • 1
    Thanks @Michael_B, having a fixed height would be a deal breaker for many wanting to use flex-box for this layout which can easily be achieved with other methods (such as floats) without forcing fixed heights. – Andrew Feb 03 '17 at 04:06
  • @Michael_B I need to use this layout but I want to set height according to cell-1`s content. Any suggestions on how to achieve it? – Nikita Tonkoskur Nov 13 '18 at 12:24
  • 1
    @bloodwithmilk, look into [CSS Grid](https://stackoverflow.com/q/42946454/3597276). – Michael Benjamin Nov 13 '18 at 12:27
-3

First we create a container .Box and set width and height. Honestly, it is just for demo i set 80vw and 80vh. And that container should be a flex element with column orientation flex-flow: column wrap;. And we set the max-width of the largest blocks (.BoxItem--large { max-width: 80%; height: 100%; }) 100% of parents height. It is for wrapping the other elements on the new line/column. So elements from another column should fill all space, so we set .BoxItem--small { max-width: 20%; height: auto; } - yes, 80% + 20% == 100%, that the math. lets change behaviour on the low-width screens. @media screen and (max-width: 600px) { .Box { flex-flow: column nowrap; } } we dont need to wrap elements, so just change that. After that we want every BoxItem element to inherit parents width. .BoxItem { width: 100%; max-width: 100%; } max-width: 100%; for cascading, we dont want care about some old rules like .BoxItem--large { max-width: 80%; } and .BoxItem--small { max-width: 20%; }. And set some order changes.

*,
*:before,
*:after {
  box-sizing: inherit;
}
html {
  box-sizing: border-box;
}
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
body {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
      -ms-flex-pack: center;
          justify-content: center;
  background-color: #F72F4E;
  overflow: hidden;
}


.Box {
  width: 80vw;
  height: 80vh;
  background-color: rgba(0,0,0,.2);
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-flow: column wrap;
      -ms-flex-flow: column wrap;
          flex-flow: column wrap;
  -webkit-box-align: baseline;
  -webkit-align-items: baseline;
      -ms-flex-align: baseline;
          align-items: baseline;
}

.BoxItem {
  background-color: #fff;
  border: 1px solid #000;
}
.BoxItem--large {
  max-width: 80%;
  height: 100%;
}
.BoxItem--small {
  max-width: 20%;
  height: auto;
}
@media screen and (max-width: 600px) {
  .Box {
    -webkit-flex-flow: column nowrap;
        -ms-flex-flow: column nowrap;
            flex-flow: column nowrap;
  }
  .BoxItem {
    width: 100%;
    max-width: 100%;
  }
  .BoxItem--large {
    height: auto;
  }
  .BoxItem--1 {
    -webkit-box-ordinal-group: 3;
    -webkit-order: 2;
        -ms-flex-order: 2;
            order: 2;
  }
  .BoxItem--2 {
    -webkit-box-ordinal-group: 2;
    -webkit-order: 1;
        -ms-flex-order: 1;
            order: 1;
  }
  .BoxItem--3 {
    -webkit-box-ordinal-group: 4;
    -webkit-order: 3;
        -ms-flex-order: 3;
            order: 3;
  }
}
<div class="Box">
  <div class="BoxItem BoxItem--large BoxItem--1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit. Dolores ea unde iste esse illo sit, repellat molestias deleniti, voluptas expedita commodi odio possimus amet?</div>
  <div class="BoxItem BoxItem--small BoxItem--2">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit.</div>
  <div class="BoxItem BoxItem--small BoxItem--3">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto omnis rerum ea assumenda velit.</div>
</div>
0x860111
  • 386
  • 1
  • 3
  • 15
  • Thanks, it would help to have a simple explanation though. Seems to use the same technique as the other answer. – dloewen Nov 27 '15 at 19:33
  • @dloewen First we create a container `.Box` and set width and height. honestly, it is just for demo i set `80vw` and `80vh`. And that container should be a flex element with column orientation `flex-flow: column wrap`; And we set the max-width of the largest blocks (.BoxItem--large { max-width: 80%; height: 100%; }) and 100% of parents height. It is for wrapping the other elemenst on the new line/column. So elements from another column should fill all space, so we set `.BoxItem--small { max-width: 20%; height: auto; }` - yes, 80% + 20% == 100%, that the math. – 0x860111 Nov 28 '15 at 04:48
  • @dloewen ok. lets change bahaviour on the low-width screens. `@media screen and (max-width: 600px) { .Box { flex-flow: column nowrap; } }` we dont need to wrap elements, so just change that. After that we want every BoxItem element to inherit parents width. `.BoxItem { width: 100%; max-width: 100%; }`. `max-width: 100%;` for cascading, we dont want care about some old rules like `.BoxItem--large { max-width: 80%; }` and `.BoxItem--small { max-width: 20%; }`. And set some order changes. It is it. – 0x860111 Nov 28 '15 at 04:54
  • The explanations above are a key component of the answer, and would be more helpful and easier to read as part of the answer. The comment section is normally reserved for minor issues. – Michael Benjamin Nov 28 '15 at 12:03
  • 2
    @Michael_B got it, thanks. Updated answer. – 0x860111 Nov 28 '15 at 15:32