Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flex Column Wrapping and Flex Basis 100% Extra Space

Tags:

css

flexbox

In the example below, on the desktop view, there's extra space at the bottom of the .main-content element that I'd like to remove. I have a feeling that it is related to height: 100% and flex-basis but not sure. flex-shrink doesn't work, and even if it did it might mess with the layout.

Could someone please explain how the browser is interpreting this layout and creating the extra space.

html,
body {
  height: 100%;
}

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

main {
  flex-grow: 1;
}

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 100%;
}

header,
footer,
[class^="sidebar-"],
.main-content {
  box-sizing: border-box;
  padding: 1rem;
}

header,
footer {
  background-color: lightgreen;
}

.sidebar-nav {
  background-color: lightblue;
}

.sidebar-content {
  background-color: lightyellow;
}

.sidebar-right {
  background-color: lightpink;
}

.main-content {
  background-color: lightgray;
}

@media( min-width: 48em) {
  .sidebar-nav,
  .sidebar-content {
    width: 26%;
    margin-right: 8%;
  }
  .main-content,
  .sidebar-right {
    flex-basis: 100%;
  }
  .main-content {
    width: 66%;
  }
  .sidebar-right {
    margin-left: 2rem;
    width: 20%;
  }
  .sidebar-right+.main-content {
    width: calc( 66% - ( 20% + 2rem));
  }
}


/* Ordering of Page Layout */

.sidebar-nav {
  order: 1;
}

.main-content {
  order: 2;
}

.sidebar-content {
  order: 3;
}

.sidebar-right {
  order: 4;
}

@media( min-width: 48em) {
  .sidebar-content {
    order: 2;
  }
  .main-content {
    order: 3;
  }
}
<header>
  Header
</header>

<main>
  <div class="container">

    <div class="sidebar-nav">
      Sidebar Navigation
    </div>
    <div class="sidebar-content">
      Sidebar Content
    </div>
    <div class="sidebar-right">
      Right Sidebar
    </div>
    <div class="main-content">
      Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br>      Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br>      Main Content<br> Main Content<br> Main Content
    </div>

  </div>
</main>

<footer>
  Footer
</footer>
like image 546
hungerstar Avatar asked Jan 21 '26 18:01

hungerstar


1 Answers

Solution

Add min-height: 0 or overflow: auto (they're mostly the same) to main and .main-content.

main {
  flex-grow: 1;
  min-height: 0; /* new */
}

.main-content {
  order: 2;
  overflow: auto;  /* new */
}

Tested on Chrome, Firefox and Edge.

body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  margin: 0;
}

main {
  flex-grow: 1;
  min-height: 0; /* new */
}

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 100%;
}

header,
footer,
[class^="sidebar-"],
.main-content {
  box-sizing: border-box;
  padding: 1rem;
}

header,
footer {
  background-color: lightgreen;
}

.sidebar-nav {
  background-color: lightblue;
}

.sidebar-content {
  background-color: lightyellow;
}

.sidebar-right {
  background-color: lightpink;
}

.main-content {
  background-color: lightgray;
}

@media(min-width: 48em) {
  .sidebar-nav,
  .sidebar-content {
    width: 26%;
    margin-right: 8%;
  }
  .main-content,
  .sidebar-right {
    flex-basis: 100%;
  }
  .main-content {
    width: 66%;
  }
  .sidebar-right {
    margin-left: 2rem;
    width: 20%;
  }
  .sidebar-right+.main-content {
    width: calc(66% - (20% + 2rem));
  }
}


/* Ordering of Page Layout */

.sidebar-nav {
  order: 1;
}

.main-content {
  order: 2;
  overflow: auto;   /* new */
}

.sidebar-content {
  order: 3;
}

.sidebar-right {
  order: 4;
}

@media(min-width: 48em) {
  .sidebar-content {
    order: 2;
  }
  .main-content {
    order: 3;
  }
}
<header>
  Header
</header>
<main>
  <div class="container">
    <div class="sidebar-nav">
      Sidebar Navigation
    </div>
    <div class="sidebar-content">
      Sidebar Content
    </div>
    <div class="sidebar-right">
      Right Sidebar
    </div>
    <div class="main-content">
      Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br>      Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br> Main Content<br>      Main Content<br> Main Content<br> Main Content
    </div>
  </div>
</main>
<footer>
  Footer
</footer>

jsFiddle demo


Problem #1: Flex minimum size algorithm

A flex item cannot be smaller than the size of its content along the main axis. A default setting for flex items in flex-direction: column is min-height: auto. You can override this with min-height: 0 or, if you want scroll bars, overflow: auto.

Full explanation here: Why don't flex items shrink past content size?


Problem #2: Unreliable use of percentage heights

Per the spec, for a percentage height to work as intended, it must have a defined height on the parent. For example, your .container element has this CSS:

.container {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 100%;
}

However, the parent of .container, which is main, has no defined height.

main {
  flex-grow: 1;
}

This leads to inconsistent and unreliable behavior across browsers.

Without a defined height on the parent the browser should, according to the spec, render the element with height: auto, the default setting.

However, in reality, different browsers have different rendering behavior. Some stick to the spec. Others try to guess what the author intended (which is known as an intervention).

Also, some browsers nowadays accept flex lengths on parents as adequate references for children with percentage heights. It's inconsistent and unreliable, however.

The best way to handle this set-up is to make sure to set a height on the parent so that the child with a percentage height has a clear reference point. And also make sure to use the height property, as flex-basis isn't always reliable in some browsers / situations.

Full explanation here: Chrome / Safari not filling 100% height of flex parent

like image 142
Michael Benjamin Avatar answered Jan 24 '26 16:01

Michael Benjamin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!