Can Flexbox do this 2-Column Setup

Hi,
I’m wanting to do a two column layout that basically stacks two separate divs on the left to create the left sidebar. Then the main div on the right would fill the rest of the space and match the sidebar height and vice versa.

Here’s the kicker though, I need those three divs nested in one wrapping div so I can stack them correctly when the media query kicks in.

I can nest the two sidebar divs in a parent div and accomplish this easy, but I can’t distribute them correctly when the media query kicks in since they are trapped in the parent.

Here’s some pics of what I am trying to accomplish…

Before media query (Desktop)

After media query (Mobiles)

The after image was easily created with this html structure…

   <div class="inner">
      <div class="side-1">Side Top</div>
      <div class="main">
         <h2>H2 Content Heading</h2>
         <p>main content text</p>
      </div>
      <div class="side-2">Side Bottom</div>
   </div>

I don’t know if there is a way flexbox can stack the two side divs though, here is the code I was working with for the after screen shot.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2-Col Stack Flex</title>
<style>
html {
   box-sizing: border-box;
}
*, *:before, *:after {
   box-sizing: inherit;
}
.wrap {
   width:96%;
   max-width: 1000px;
   margin: 0 auto;
}
header,footer {
   padding: 10px;
   font-weight: bold;
   text-align: center;
}
header {
	background: tomato;
}
footer {
	background: lightgreen;
}

/*====== Flex Rules ======*/
.inner {
   display: flex;
   flex-flow: row wrap;
   font-weight: bold;
   text-align: center;
}
.inner > * {
   padding: 10px;
   font-weight: bold;
}
.main {
   order: 3;
   flex: 3 0px;
   text-align: left;
   background: deepskyblue;
}
.side-1 {
   order: 1;
   flex: 0 180px;
   background: gold;
}
.side-2 {
   order: 2;
   flex: 0 180px;
   background: hotpink;
}

@media all and (max-width: 600px) {
   .inner {flex-flow: column wrap;}
   .side-1,.side-2 {flex: 0;}
   .main {order: 2;}
   .side-2 {order: 3;}
}


</style>
</head>
<body>
<div class="wrap">
   <header>Header</header>
   <div class="inner">
      <div class="side-1">Side Top</div>
      <div class="main">
         <h2>H2 Content Heading</h2>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
      </div>
      <div class="side-2">Side Bottom</div>
   </div>
   <footer>Footer</footer>
</div>
</body>
</html>

I’m not sure what you are requesting, Ray. I copied your “after screen shot” code to my PC and opened it in FF. It seems to demonstrate both the desktop and mobile views as shown. Did you want the side boxes distributed differently? Maybe that’s what I’m missing.

On desktop the sidebar blocks need to stack, as seen in my before (desktop) pic.

That desktop pic was created with different code, but it will not give me the mobile version I’m after.

You will see that I had to nest the sidebar divs in a parent div .left , but that will not get the mobile view I want.

EDIT:
The Gold box “Side Top” is going to be my nav menu for desktops, then it will be a toggle menu for mobiles.

The Pink box “Side Bottom” is going to be <aside> content, but I don’t want to discard it when media queries kick in. I want it to go above the footer.

Here’s the code that gives the desktop view I want…

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2-Col Stack Flex</title>
<style>
html {
   box-sizing: border-box;
}
*, *:before, *:after {
   box-sizing: inherit;
}
.wrap {
   width:96%;
   max-width: 1000px;
   margin: 0 auto;
}
header,footer {
   padding: 10px;
   font-weight: bold;
   text-align: center;
}
header {
	background: tomato;
}
footer {
	background: lightgreen;
}

/*====== Flex Rules ======*/
.inner {
   display: flex;
   flex-flow: row wrap;
   font-weight: bold;
   text-align: center;
}
.main {
   order: 2;
   flex: 2 0;
   text-align: left;
   padding: 10px;
   background: deepskyblue;
}
.left {
   display: flex;
   flex-flow: row wrap;
   order: 1;
   font-weight: bold;
}
.side-1 {
   order: 1;
   flex: 1 200px;
   padding: 10px;
   background: gold;
}
.side-2 {
   order: 2;
   flex: 1 200px;
   padding: 10px;
   background: hotpink;
}

@media all and (max-width: 600px) {
   .inner,.left {flex-flow: column wrap;}
   .side-1,.side-2 {flex: 0;}

   .side-1 {order: 1;}
   .main {order: 2;}
   .side-2 {order: 3;}

}


</style>
</head>
<body>
<div class="wrap">
   <header>Header</header>
   <div class="inner">
      <div class="left">
         <div class="side-1">Side Top</div>
         <div class="side-2">Side Bottom</div>
      </div>
      <div class="main">
         <h2>H2 Content Heading</h2>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
      </div>
   </div>
   <footer>Footer</footer>
</div>
</body>
</html>

The code from my first post produces this on desktops…

I’m trying to come up with code that produces the results of the desktop and mobile pics from post#1.

I know it sounds confusing, I had to write two pieces of code to create the desktop/mobile screenshots. The screenshots represent what I am trying to get one code to do.

You need the flex flow as column wrap to get the stacked sidebar, then set the order.

Thanks, Ray.
It shouldn’t have been confusing to me. I have to chalk it up to a brain fart akin to an absence of short term memory.

1 Like

The problem is it needs to be a flex column to get that stacking. But to make the column wrap so the main starts a new column you need to constrain the parent height which I imagine you will want to avoid.
This may be more a case for grid rather than flex.

2 Likes

I knew this wasn’t as easy as it looks. I see it work with a height like you said, but of course that’s not feasible.

I have no interest in using grid due to browser support at this time.

I can get the desktop view by floating the sidebar blocks, they would have to come first in the html source though. Then I can’t rearrange the order when media queries kick in for mobile.

EDIT:
Here is the code using height and it gives the desktop and mobile views I’m after, but it is useless with height set.
Although I am having trouble keeping the sidebars at a fixed width while main content fills the rest of the space.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2-Col Stack Flex</title>
<style>
html {
   box-sizing: border-box;
}
*, *:before, *:after {
   box-sizing: inherit;
}
.wrap {
   width:96%;
   max-width: 1000px;
   margin: 0 auto;
}
header,footer {
   padding: 10px;
   font-weight: bold;
   text-align: center;
}
header {
	background: tomato;
}
footer {
	background: lightgreen;
}

/*====== Flex Rules ======*/
.inner {
   display: flex;
   flex-flow: column wrap;
   font-weight: bold;
   text-align: center;
   height:500px
}
.inner > * {
   padding: 10px;
   font-weight: bold;
}
.main {
   display: flex;
   flex-direction: column;
   order: 3;
   flex: 1 2 0px;
   text-align: left;
   background: deepskyblue;
}
.side-1 {
   display: flex;
   flex-direction: column;
   order: 1;
   flex: 1 0 180px;
   /*width:180px;*/
   background: gold;
}
.side-2 {
   display: flex;
   flex-direction: column;
   order: 2;
   flex: 1 0 180px;
   /*width:180px;*/
   background: hotpink;
}

@media all and (max-width: 600px) {
   .inner {flex-flow: column wrap;}
   .side-1,.side-2 {flex: 0;}
   .main {order: 2;}
   .side-2 {order: 3;}
}


</style>
</head>
<body>
<div class="wrap">
   <header>Header</header>
   <div class="inner">
      <div class="side-1">Side Top</div>
      <div class="main">
         <h2>H2 Content Heading</h2>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
      </div>
      <div class="side-2">Side Bottom</div>
   </div>
   <footer>Footer</footer>
</div>
</body>
</html>

It would be if all the browsers supported display:contents which was built for purposes like these.


@media all and (max-width: 600px) {
	.left{display:contents}
}

If you view your page in Firefox only then it works as you want.:slight_smile:

I would suggest that as its only the mobile view that needs that layout then you use flexbox as you have done for larger screens and then just use grid for the smaller view as support is good in mobile. I haven’t tested if its possible with grid yet with the structure you are using and it may be the same issue as flex. I am not near a computer at the moment but I’ll try and have a go later or tomorrow. :slight_smile:

1 Like

Thanks Paul, maybe this can be done with some combination of methods for desktop and mobile.

I started trying to rebuild my site and make it responsive over a year ago but didn’t have the time to finish it.

Here’s my old test page using flex. The problem is the extra div that sidebar blocks are nested in, it causes me to loose my aside content on mobiles.

Flex Test Page

It shows how I want the menu to behave

Had a quick look at grid and it seems it suffers from the same problems as flex in that items in the grid can’t be moved out of the current grid parent. I did read there was something called a subgrid which may offer that facility but is not implemented by any browser yet. It may be that I am not just seeing the obvious but I’ve only glanced briefly at grid as it seems overly complex to me and usually the layout can be done more easily with other means.

It’s funny though in that I have a layout from about 15 years ago that can nearly do what you want?

https://codepen.io/paulobrien/pen/mpMxxQ

It’s a bit hacky and all smoke and mirrors but I love the way that the old school css could do things. Flex and grid are great but very specific in what they do. I’d rather just be given bricks and let me build the house how I want :slight_smile:

4 Likes

Ah heck, that’s clean code. Nothing hacky about floats and negative margins, my site has been running like that for 10 years now. :grinning:

Brilliant Paul !
.side-2{display:table-footer-group;}

I enjoyed all the trickery that was needed back then, that’s what made everything fun and challenging.

So are the floats eliminating any anonymous table-cells that the browser would have constructed.

I was a bit shocked by the idea that Grid can’t do this, isn’t that exactly what it’s for?
Still WIP, yet to sort the query.
https://codepen.io/SamA74/pen/barMBp

2 Likes

Yes grid can do it but not without a reasonable neat fallback. :slight_smile:

I meant to say grid can’t do it unless all elements are direct children of the grid

I loved Lego as a kid. I used to make anything I could dream of just out of basic bricks. Now I look at Lego, with all these custom components, and it just turns me off.

3 Likes

I guess the whole point of this html structure…

<div class="inner">
   <div class="side-1">Side Top</div>
   <div class="main">Main Content</div>
   <div class="side-2">Side Bottom</div>
</div>

Was that mobiles could just get display:block and be done. So mobile support for grid is not really the issue. Even though they have better support than desktop.

Which of course is exactly what Sam has done. :slight_smile:

2 Likes

I think I’ve got something I can work with now. Was able to put together an example using all floats on the three nested divs.

Doing that I was able to keep the html just like I posted it above in #16.

Got real close using inline-table but hit one little snag that caused my lower side bottom div to be out of the flow. The side top div would no longer push it down.

I think this layout using all floats wound up being the most stable code. The linear-gradient backgrounds sure are handy for faux columns. A calc() width helped eliminate the need for an extra wrapping div we used to need also.

I’ll post the code for posterity should my link disappear someday.

Thanks for everyone’s help :slight_smile:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2-Col Stack - All Floats</title>
<style>
html {
   box-sizing: border-box;
}
*, *:before, *:after {
   box-sizing: inherit;
}
.wrap {
   max-width: 1000px;
   margin: 0 auto;
   background: #ccc;
   border:1px solid;
}
header,footer {
   padding: 10px;
   font-weight: bold;
   text-align: center;
}
header {
   background: tomato;
   border-bottom:1px solid;
}
footer {
   background: lightgreen;
   border-top:1px solid;
   clear:both;
}

/*====== Layout Rules ======*/
.inner {
   display: table; /*contain floats*/
   width: 100%;
   font-weight: bold;
   position: relative;
   background:
      linear-gradient(to right,
      transparent, transparent 200px, /*left block*/
      #000 200px, #000 201px,  /*1px border*/
      #EEE 201px); /*right block*/
   padding-bottom: 90px;/*guard for ap blk*/
   text-align:center;
}
.inner > div {
   padding: 10px;
}
.side-1{
   float: left;
   width: 200px;
   min-height: 80px;
   background: gold;
   border-bottom: 1px solid;
}
.main {
   float: right;
   width: calc(100% - 201px);
   background: #EEE;
   margin-bottom: -90px; /*soak up inner padding guard*/
   text-align:left;
}
.side-2 {
   float: left;
   clear: left;
   width: 200px;
   min-height: 80px;
   background: #ccc;
   border-bottom: 1px solid;
}

.side-1:hover,
.main:hover,
.side-2:hover {padding-bottom: 200px;}

.ap-blk {
   position:absolute;
   width:80px;
   height:80px;
   left:60px;
   bottom:0;
   background:hotpink;
}
@media all and (max-width: 600px) {
   .side-1,.main,.side-2 {
      display:block;
      position:static;
      float:none;
      width:100%;
      height:auto;
      margin:0;
      border-bottom:1px solid;
   }
   .inner {background:none; padding:0;}
   .ap-blk {display:none;}
   footer {border:none;}
}
</style>
</head>
<body>

<div class="wrap">
   <header>2-Col Stack - All Floats</header>
   <div class="inner">
      <div class="side-1">
         Side Top<br>Hover
      </div>
      <div class="main">
         <h2>Content Heading</h2>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
         <p>main content text</p>
         <p>Hover here and in sidebar blocks to expand floats</p>
      </div>
      <div class="side-2">
         Side Bottom<br>Hover
      </div>
      <div class="ap-blk">Bottom Block</div>
   </div>
   <footer>Footer</footer>
</div>

</body>
</html>
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.