How to reorder divs using flex box?

In general, you can’t do this with Flexbox alone, though there might be a compromise based on each given case.

With Flexbox alone, using fixed height, you can accomplish this

* {
  box-sizing: border-box;
}

body, html {
  margin: 0;
}

.flex {
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);  
  display: flex;
  flex-flow: column wrap;
}
.flex div {
  flex: 1;
  width: 50%;
}
.flex div:nth-child(2) {
  order: -1;
}
.flex::before {
  content: '';
  height: 100%;
}

@media (max-width:768px) {
  .flex div {
    width: auto;
  }
  .flex::before {
    display: none;
  }
 .flex div:nth-child(2) {
    order: 0;
  }
}


/*  styling  */
.flex-child {
  color: white;
  font-size: 2em;
  font-weight: bold;
}
.flex-child:nth-child(1) {
  background: #e6007e;
}
.flex-child:nth-child(2) {
  background: #f4997c;
}
.flex-child:nth-child(3) {
  background: #86c06b;
}
<div class="flex">
  <div class="flex-child">
    <div>Top/Right</div>
  </div>
  <div class="flex-child">
    <div>Center/Left</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right</div>
  </div>
</div>

In this case, where no fixed height is allowed, you can combine Flexbox and float.

By set up it for mobile using Flexbox where you add the center item first in the markup and then, with order, move it between the top and bottom.

With a media query you then simply make the flex container a block element and use float to position the left to the left and the right to the right.

* {
  box-sizing: border-box;
}

body, html {
  margin: 0;
}

.flex {
  max-width: 1024px;
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);
  
  display: flex;
  flex-direction: column;
}

.flex-child {
  color: white;
  font-size: 2em;
  font-weight: bold;
  padding: 5%;
  flex-basis: 33.333%;

  display: flex;
  align-items: center;
}

.flex-child:nth-child(1) {
  background: #e6007e;
  order: 1;
}
.flex-child:nth-child(2) {
  background: #f4997c;
}
.flex-child:nth-child(3) {
  background: #86c06b;
  order: 2;
}

@media (min-width: 768px) {
  .flex {
    display: block;
  }
  .flex-child {
    width: 50%;
  }
  .flex-child:nth-child(1) {
    float: left;
    height: 100%;
  }
  .flex-child:nth-child(2),
  .flex-child:nth-child(3) {
    float: right;
    height: 50%;
  }
}
<div class="flex">
  <div class="flex-child">
    <div>Center/Left</div>
  </div>
  <div class="flex-child">
    <div>Top/Right</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right</div>
  </div>
</div>

Update

Here is another version combining Flexbox with position: absolute, which also vertically center the items in desktop mode

Updated, added a script to control so the absolute positioned element won’t get bigger than the right items, and if so, adjust the flex containers height.

Note, the script is by no means optimized, it is only there to show how a fix in certain situations

(function() {

  window.addEventListener("resize", resizeThrottler, false);

  var fp = document.querySelector('.flex');
  var fi = fp.querySelector('.flex-child:nth-child(1)');
  var resizeTimeout;
  function resizeThrottler() {
    // ignore resize events as long as an actualResizeHandler execution is in the queue
    if ( !resizeTimeout ) {
      resizeTimeout = setTimeout(function() {
        resizeTimeout = null;
        actualResizeHandler();
     
       // The actualResizeHandler will execute at a rate of 15fps
       }, 66);
    }
  }

  function actualResizeHandler() {
    // handle the resize event
    if (fp.offsetHeight <= fi.offsetHeight) {
      fp.style.cssText="height: "+fi.offsetHeight+'px';
    } else {
      fp.style.cssText="height: auto";
    }
  }

  window.addEventListener('load', function() {
    actualResizeHandler();
  })
  
}());
* {
  box-sizing: border-box;
}

body, html {
  margin: 0;
}

.flex {
  position: relative;
  max-width: 1024px;
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);
  
  display: flex;
  flex-direction: column;
}

.flex-child {
  color: white;
  font-size: 2em;
  font-weight: bold;
  padding: 5%;
}

.flex-child:nth-child(1) {
  order: 1;
}
.flex-child:nth-child(3) {
  order: 2;
}

.flex-child:nth-child(1) div {
  background: #e6007e;
}
.flex-child:nth-child(2) div {
  background: #f4997c;
}
.flex-child:nth-child(3) div {
  background: #86c06b;
}

@media (min-width: 768px) {
  .flex {
    justify-content: center;
  }
  .flex-child {
    width: 50%;
  }
  .flex-child:nth-child(1) {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
  }
  .flex-child:nth-child(n+2) {
    margin-left: 50%;
  }
}
<div class="flex">
  <div class="flex-child">
    <div>Center/Left<br>with more<br>content<br>than any<br>of the<br>other items<br>other items<br>other items<br>other items<br>other items</div>
  </div>
  <div class="flex-child">
    <div>Top/Right<br>with more<br>content</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right<br>with more</div>
  </div>
</div>

With script one can also reorder/move items between elements.

Stack snippet

You can also combine this with a media query, and use it to do the actual re-order of the elements

$( document ).ready(function() {
  $(window).resize(function() {
    if ($( window ).width() < 600 ) {
      $(".one").insertBefore("#b");
    } else {
      $(".one").insertBefore(".two");
    }
  });
});
.outer, #flex, #flex2 {
  display: flex;
  flex-direction: column;
}
#a {
  order: 4;
  background: #ccc;
}
#b {
  order: 1;
  background: #aaa;
}
#c {
  order: 3;
  background: #d33;
}
.one {
  order: 2;
  background: #aaa;
}
.two {
  order: 5;
  background: #aaa;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="outer">
  <div id="flex">
    <div id="a">A</div>
    <div id="b">B</div>
    <div id="c">C</div>
  </div>

  <div id="flex2">
    <div class="one">Show me 2nd</div>
    <div class="two">Show me 5th</div>
  </div>

</div>

Update 2 (answered at another question but later moved here)

If we talk about smaller items, like a header or smaller menus, one can do what many website platform providers like “squarespace”, “weebly”, “wordpress”, etc does. Their templates holds different markup structures, where an item sometimes exist twice, one visible for desktop, another for mobile.

Also, being so small, there will be less to nothing when it comes to performance (and personally I don’t see anymore issue with this than having duplicate CSS rules, one for each screen size, and happily do this instead of introducing script).

Fiddle demo

Stack snippet

.container {
  display: flex;
}
.container > div {
  width: 50%;
}
.container div:nth-child(-n+2) {
  border: dashed;
  padding: 10px;
}
.container > div:nth-child(1) {
  display: none;                                  /*  hide outer "Flower"  */
}

@media (max-width:768px) {
  .container {
    flex-direction: column;
  }
  .container div {
    width: auto;
  }
 .container div:nth-child(1) {
    display: block;                               /*  show outer "Flower"  */
  }
  .container div:nth-child(3) div:nth-child(1) {
    display: none;                                /*  hide inner "Flower"  */
  }
}
<div class="container">
  <div>Flower</div>
  <div>Tree</div>
  <div>
    <div>Flower</div>
    <div>Bee</div>
  </div>
</div>

Leave a Comment