Why the same flex settings create different results

Inside a, the first children (b & c) have the following settings:

b: height: 60px;

c: height: 100%;

The result of this is that b becomes 60px and c takes up the remaining height.

Now, when I do the exact same thing for the first children (d & e) inside c, the result is not the same.

e overflows its parent (which b and c doesn’t do inside a) and I don’t understand why. Can someone pls explain why it behaves differently here and how can I make it not outgrow its parent?

Code here (Codepen)

OR:

<div class="a">

  <div class="b"></div>
  <div class="c">
    <div class="d"></div>
    <div class="e"></div>
  </div>

</div>


* {
  margin: 0;
}

.a {
  display: flex;
  flex-direction: column;
  background: blue;
  width: 100vw;
  height: 100vh;
}

.b {
  height: 60px;
  background: orange;
  display: flex;
  flex-direction: column;
}

.c {
  width: 200px;
  height: 100%;

  background: purple;
  border: 1px solid black;
}

.d {
  background: pink;
  height: 60px;
  width: 50%;
}

.e {
  background: green;
  height: 100%;
  width: 50%;
}

Element a is a flexbox but element c is not.

Try setting c to flex.

2 Likes

C is not a flex box so you get 60px + 100% making it 60px too large.

Avoid using height:100% as it seldom does what you require. Use flex (flex:1 0 0) to stretch and use nested flexboxes when you want to maintain the stretch.

e.g.

* {
  margin: 0;
}

.a {
  display: flex;
  flex-direction: column;
  background: blue;
  width: 100vw;
  height: 100vh;
}

.b {
  height: 60px;
  background: orange;
  display: flex;
  flex-direction: column;
}

.c {
  width: 200px;
  /*height:100%;*/
  flex: 1 0 0;
  background: purple;
  border: 1px solid black;
  display: flex;
  flex-direction: column;
}
.d {
  background: pink;
  height: 60px;
  width: 50%;
}
.e {
  background: green;
  /*height: 100%;*/
  flex: 1 0 0;
  width: 50%;
}

There are other methods as usual with flex.

Also note that as you have used height:100vh on .a then your content can never grow more than that viewport size because you have not provided scrollbars for it (it will just overflow and the backgrounds will not follow). Use min-height:100vh instead if you only wanted an initial viewport height.

3 Likes

Yes, you’re both right.

However, the problem remains on the “real example” (my website). I use the exact same flex setup on one of my pages, but it overflows in the same way as my example in this post.

On my page, there are two elements in the body, ‘nav’ and ‘main’. ‘Nav’ has height 54px, ‘main’ has 100%. Same problem as in this post, ‘main’ should take the remaining space, but takes 100% instead.

The solution to the question in this post was to use flex on the parent, but on my page, the parent is already flex.

The page i’m talking about is a user account page, so please log in here https://codeeffect.net/login to get there.

User: test@test.com
Pass: 123456

For <main> set the height:

height: calc(100vh - 54px);

( 54px is the height of your <nav> )

Alternatively consider using position:sticky on your <nav> instead so you use the browser window’s scrollbar . . .

3 Likes

Thanks for your reply.

I know how I can fix it using other solutions, but I want to know why the flex behaves differently on my website. ‘Main’ should take up the remaining height, but it doesn’t. The setup is exactly the same as the example in this post. So what’s difference, I don’t understand.

As mentioned previously your height:100% on main does nothing and you height:100% on body does nothing also because html has no height. Both those will fail and revert to height:auto.

As @Archibald suggests you should use the vh unit instead and subtract the height of the nav using calc and then it will all work and you can get rid of the height:100% on the elements already mentioned.

However if you had used a flex wrapper properly you wouldn’t need a magic number fix using calc. I’ll show a demo later when I get back to the computer. :slight_smile:

That’s because the whole page is not contained in a flex wrapper. At the moment you have two different elements who don’t share the same flex parent so their content heights are not controlled by flex properties of the main wrapper.

You could use the body as a flex parent with flex-direction column and then it’s direct children can be controlled with flex properties as shown in my initial reply.

They are both children of the body, which is display flex :slight_smile:

I figured it out. I forgot to add overflow auto to ‘main’. Now it stays within its range. Problem solved :slight_smile:

Ok sorry, I’ll have another look when I get back in a couple of hours. :slight_smile:

1 Like

And no need for calc(54px - x). Benifit of this is, every time I play around with the nav-size, I don’t have to go back and update calc

1 Like

Then you don’t need height:100% on <main>.

No problem buddy, your time and that you get to know the issue means a lot

Correct, not at the moment at least

Yes that’s what I was getting at with the magic number comment. Much better to be automatic and no reliance on specific numbers (apart from the initial height of the main container).

Here was the minimum demo I mentioned before just for reference.

Notice how there are no heights needed apart from the initial body wrapper. All the stretching is done with flex properties.

You don’t need height on main but you do need flex:1 0 0or if you have less content than the viewport height the content will float in the middle.

Rather than have the scrollbar on the scrollable panel I would prefer to have the scrollbar on the viewport as most people would expect. If you use position:sticky for the header (and footer if needed) as @Archibald suggested above you can have the scrollable panel scrol but be activated by the viewport scrollbar in the normal way.

Proof of concept.

(View on Codepen for full effect.)