Search code examples
htmlcssflexbox

Understanding flex, height and overflow


I have a behavior that puzzles me. The code below is the result of debugging a larger app. I know I can simplify it and make it work. However, I would like to understand and learn.

There are two rectangles (height: 100px and height: 400px) stacked on top of each other in a column flex box. When the window gets smaller than 500px, the browser will add a scrollbar. Ok. But if it gets smaller than 400px, the blue box shows a scrollbar.

I would have expected either the body-scrollbar or the blue-box-scrollbar, but not both. Can anyone explain

HTML

*,
::before,
::after {
    box-sizing: inherit;
}

html,
body {
    margin: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    /* overflow: visible; */
}

.full-size {
    width: 100%;
    height: 100%;
}

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

.content {
    flex: 1;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <title>Hi</title>
    <base href="/" />
    <link rel="stylesheet"
        href="style.css" />
    <meta name="viewport"
        content="width=device-width, initial-scale=1" />
</head>

<body>
    <div class="full-size container">
        <div style="width:300px; height: 100px; background-color: green; flex-shrink: 0;">Upper content</div>
        <div class="full-size content">
            <div class="full-size"
                style="overflow: auto; background-color: blue;">
                <div style="width:300px; height: 400px; background-color: yellow;">Lower content</div>
            </div>
        </div>
    </div>
</body>

</html>


Solution

  • It's related to the use of the cascade height: 100% until the content element. Inside your container, you have an element with a height equal to 100px and another with a height equal to 100%. This will logically result in an overflow but the shrink effect will strike and the second element will get smaller than 100%.

    But on small screen the yellow box will trigger another effect and will prevent the shrinking due to the default min-height configuration (Why don't flex items shrink past content size?) and will block your element at height: 100% which will trigger the body-scrollbar and the yellow box inside is bigger than height: 100% which will trigger the blue-scrollbar.

    To avoid this, add min-height: 0 to content

    html,
    body {
      margin: 0;
      height: 100%;
      
    }
    .full-size {
      height: 100%;
    }
    
    .container {
      display: flex;
      flex-direction: column;
    }
    
    .content {
      flex: 1;
      min-height: 0;
    }
    <div class="full-size container">
      <div style="width:300px; height: 100px; background-color: green; flex-shrink: 0;">Upper content</div>
      <div class="full-size content">
        <div class="full-size" style="overflow: auto; background-color: blue;">
          <div style="width:300px; height: 400px; background-color: yellow;">Lower content</div>
        </div>
      </div>
    </div>

    Now the blue box will always shrink and you will never get the body-scrollbar