3

I've been on this for a while now and tried a lot of the solutions I've seen across different Stackoverflow questions / blogposts / ... But I honestly can't figure out what's going wrong.

I've got a flexed div with two divs in there. The top div A has a fixed height, the other div B fills the rest using flex: 1;. If the screen is resized and it's smaller than the height of A + B together, then B will start overflowing. I want it to scroll, but I also want the content to be fully visible when scrolling. For some reason which I can't figure out, the content renders out of the top of div B as you can see in this screenshot of my fiddle:

enter image description here

Some of the previously asked questions got me somewhere. For example setting the body to height: auto;, but then when my screen is bigger than A + B it can't be center aligned anymore. min-height: 0; also doesn't seem to help in this case.

How can I make sure my container overflows but will fully show the content of it?

Kevin
  • 1,219
  • 1
  • 16
  • 34
  • So if I understand you correctly you want to be able to scroll through all of your content if the screen size becomes smaller than A + B not just be able to scroll up and down a little and still have some of your content hidden? Is that correct or am I missing something? – KJEK-Code Jan 27 '19 at 18:00
  • Of course, when the screen is smaller than A + B it's impossible to see A + B in its entirety if you think that's what I mean. I think you will better understand what I'm trying to achieve if you check out the codepen I attached and resize your screen so it's smaller than the container. If you then scroll upwards, you're not able to see the top side of the 3 divs. You can however see the bottom 2 divs (depends on how small your screen is), but it's impossible now to see the top rectangle. I would like to be able to see all 3 rectangles in that codepen. – Kevin Jan 27 '19 at 18:03
  • I fixed it.. however I feel like your putting in a lot more css than is needed.. Let me know if you need anymore help – KJEK-Code Jan 27 '19 at 18:10
  • The main problem is `align-items: center` on `.second`. Remove that and add `margin: auto` to `.container`, plus `flex-shrink: 0` to `.container-child` and you're all set (and you can remove a lot of unnecessary code) ([revised codepen](https://codepen.io/anon/pen/bzeMyJ)). Full explanation in the duplicate. – Michael Benjamin Jan 28 '19 at 18:53

1 Answers1

2

You can solve the issue by giving .second:

flex-basis: auto;
flex-shrink: 0;

Or, with shorthand: flex: 1 0 auto;

Working example:

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

body {
  display: flex;
  flex-direction: column;
}

.second {
  flex: 1 0 auto;
  background: blue;
  width: 100%;
  
  display: flex;
  justify-content: center;
  align-items: center;
  
  min-height: 0;
  
  overflow: auto;
}

.container {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 500px;
  min-height: 0;
  /* added this to make it obvious. Obviously, not needed */
  padding: 2rem 0;
}

.container-child {
  height: 110px;
  background: green;
  width: 100%;
}

.container-child:not(:last-child) {
  margin-bottom: 30px;
}
<div class="second">
  <div class="container">
    <div class="container-child"></div>
    <div class="container-child"></div>
    <div class="container-child"></div>
  </div>
</div>

I added some top and bottom padding to .container to make it obvious that it's working - but it's not needed.

Now let's look at why this is happening. When you apply .second { flex:1; } it means:

flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;

... which allows it to have a smaller size than its contents.

Whenever you have a bigger child centered in a smaller parent, the browser won't provide a scrollbar to top (or to left, when horizontal), because then , if the top of the parent and the top of the child coincide and the child is bigger than the parent, the child is no longer centered, is it? The same happens when using other centering techniques and you center a bigger child in a smaller parent.
To fix the problem, you need to prevent the child from outgrowing the parent.

In this case, it meant sizing .second based from its content (flex-basis: auto) and not allowing it to shrink: (flex-shrink: 0;).

To better visualize the issue, consider this example:

.left, .right {
  position: relative;
  border: 1px solid red;
  padding: 1rem 5rem;
}
.left {
  left: -5rem;
}
.right {
  right: -5rem;
}
<div class="left">
  I'm taken left
</div>
<div class="right">
  I'm taken right
</div>

If the browser provided scrollbars to allow you to scroll to beginning of .left, it would mean that left: -5rem did not apply. I hope that makes sense, I can't explain it better.

tao
  • 82,996
  • 16
  • 114
  • 150
  • That does indeed seem to do the trick. I don't understand how this now is the solution... Also, I apparently didn't 100% correctly make a replica of the situation in my project, because there that's not the solution... I'm not sure if I'd be able to get it in a working fiddle though then... – Kevin Jan 27 '19 at 18:21
  • I will explain why the issue happens but it will take a few minutes, as it's not as simple as it looks. – tao Jan 27 '19 at 18:22
  • I figured. I've been reading up and trying to 100% fully understand everything around flexbox because it's such a strong tool to master. – Kevin Jan 27 '19 at 18:24
  • It's not a `flexbox` specific problem. It's the problem of centering a bigger child in a smaller parent. I updated my answer. Happens the same with `top: 50%; left: 50%; transform: translate(-50%,-50%)`. – tao Jan 27 '19 at 18:28
  • The issue is getting clearer to me and I feel like I'm at 93% of getting to the aha!-moment, but I don't understand why the right part *does* render correctly now. To me it makes sense what you're saying about the left part, but then I am not able to explain anymore why the right side is rendering. – Kevin Jan 27 '19 at 18:47
  • 1
    It's a decision that was taken a long time ago and has been carried on since: it was decided that, when overflowing stuff to right or bottom, users expect to be able to scroll to them, but when doing the same for left of top, the majoritary intent is to hide them, so scroll should not be allowed. Bottom line: it's how it is and you can't change it. :) – tao Jan 27 '19 at 18:49
  • 1
    Makes sense though when you think of it. Thanks a lot for the extensive explanation, much appreciated! Also managed to fix it now in my personal project, only had to apply `flex-shrink: 0;` to the div next to it because your fix pushes the other div away without the shrink on the other div. Thanks once more. – Kevin Jan 27 '19 at 18:51