Move sidebar in between other elements on smaller screens

Viewed 349

I'm not totally sure this is possible, but I figured I'd ask.

I'm wondering to move a sidebar in-between some content when it hits a breakpoint.

So, for example something like this:

+---------------------+ +-------------+
|                     | |             |
|    Top Content      | |             |
|                     | |  Sidebar    |
|                     | |             |
+---------------------+ |             |
+---------------------+ |             |
|                     | |             |
|                     | |             |
|                     | |             |
|     Other           | |             |
|     Content         | |             |
|                     | |             |
|                     | |             |
|                     | |             |
|                     | |             |
|                     | |             |
|                     | |             |
+---------------------+ +-------------+

To this:

  +-------------------------+
  |                         |
  |        Top Content      |
  |                         |
  +-------------------------+
  +-------------------------+
  |                         |
  |                         |
  |     Sidebar             |
  |                         |
  |                         |
  |                         |
  +-------------------------+
  +-------------------------+
  |                         |
  |                         |
  |                         |
  |                         |
  |       Other             |
  |       Content           |
  |                         |
  |                         |
  |                         |
  |                         |
  +-------------------------+

So I know that I can set the orders, but I'm not quite sure how to get the "flow" to correctly set.

I'm wondering something like this:

.flex-container {
  display: flex;
  flex-direction: row;
}

.top-content {
  order: 1;
}

.sidebar {
  order: 3;
  justify-self: flex-end;
}

.other-content {
  order: 2;
}

@media screen and (max-width: 767px) {
  .flex-container {
    flex-direction: column;
  }
  .sidebar {
    order: 2;
  }
  .other-content {
    order: 3;
  }
}
<div class="flex-container">
  <div class="top-content">
    ...
  </div>
  <div class="sidebar">
    ...
  </div>
  <div class="other-content">
    ...
  </div>
</div>

But I'm not sure if that's even plausible? Wondering if this is something that needs to be done with CSS Grid instead? Anyways, just a thought. Was hoping to use the same content structure without having to hide/show the same thing with breakpoints and writing more markup on the page.

2 Answers

It's simpler and easier with CSS Grid.

.grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 3fr;
  grid-gap: .5em;
  height: 100vh;
  background-color: gray;
}

.top-content {
  grid-column: 1;
  background-color: orangered;
  border: 1px dashed black;
}

.sidebar {
  grid-column: 2;
  grid-row: 1 / -1;
  background-color: aqua;
  border: 1px solid black;
}

.other-content {
  grid-column: 1;
  background-color: lightgreen;
  border: 1px dashed black;
}

body {
  margin: 0;
}

@media (max-width: 500px) {
  .grid-container {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }
  .sidebar {
    grid-column: 1;
    grid-row: 2;
  }
}
<div class="grid-container">
  <div class="top-content">top content</div>
  <div class="sidebar">sidebar</div>
  <div class="other-content">other content</div>
</div>

jsFiddle demo

Well, I figured out how to achieve this, see:

        .flex-container {
          display:flex;
          flex-flow: row wrap;
          box-sizing: border-box;
        }

    
    @media screen and (max-width: 600px) {
      break {display:none;}
    
    }
    
    div {
      border: 1px black solid;
      
    }
    
    .flex-container > div {
      box-sizing: border-box;
    }
    
.flex-container > div, break{ 
  display: inline-block; 
}
    
break{
  flex-basis: 100%;
  width: 0px; 
  height: 0px; 
  overflow: hidden;
}
     <div class="flex-container">
      <div class="top-content" style="width: 350px; height: 500px;">
        ...
      </div>
      <div class="sidebar" style="width: 350px; height: 500px;">
        ...
      </div>
      <break></break>
      <div class="other-content" style="width: 350px; height: 500px;">
        ...
      </div>
    </div>

The only thing I did was creating a custom HTML5 tag called <break>. This tag creates a new line between the divs that you specify. So, if you media-query is reached (due to lower resolutions) you only need to hide it.

The original idea was taken from: https://codepen.io/hrgdavor/pen/waXEqz

EDIT:

I realized about the leaking rowspan behaviour on my example. So I decided to search and I found this, and I created this demo:

.flex-container {
  display:flex;
  flex-flow: row wrap;
  box-sizing: border-box;
  flex-direction: column;
  flex-wrap: wrap;
  height: 1000px;
}
 
 @media screen and (min-width: 600px) {
  .top-content, .other-content {flex: 0 0 50%;}
  .sidebar {flex: 0 0 100%; order: 1;}
 }
  
 @media screen and (max-width: 600px) {
   .flex-container {flex-direction: row;}
   .top-content, .other-content, .sidebar {flex: 0 0 100%;}
   .other-content {order:2;}
 }
 
 .flex-container > div {
  box-sizing: border-box;
 }

 /* Only for doing example */
.flex-container > div {
  border: 1px black solid;
}
     <div class="flex-container">
      <div class="top-content">
        ...
      </div>
      
      <div class="sidebar">
        ...
      </div>
      
      <div class="other-content">
        ...
      </div>
    </div>

Note: box-sizing: border-box; is important.

Hope this helps!

Related