2

update: I see this strange behavior on Chrome 72. FireFox 64 is OK!

I have a problem with a nested flexbox.

In the snippet below I added a dummy XL height to .root.container, so that the result is exactly what I want when there are many items that overflow the available max-height.

Conversely, when there are few items, the .root.container should not extend to all available height.

In other terms, I want .root.container height to be auto, but I can't figure how.
Removing its dummy height, the overflow is triggered on .root.content instead of .sub.content.

Please, help me understand how flexbox works in this particular situation.

P.S. fiddle also available here

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

* {
  box-sizing: border-box;
}

div {
  padding: 10px;
}

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

.content {
  flex: 1;
  max-height: 100%;
  overflow: auto;
}

.root.container {
  background-color: red;
  max-height: 100%;
  height: 999999px; /* i want height to be 'auto' */
}

.sub.container {
  background-color: purple;
  height: 100%;
}

.root.header {
  background-color: lightblue;
}

.sub.header {
  background-color: lightgreen;
}

.root.content {
  background-color: yellow;
}

.sub.content {
  background-color: orange;
}
<div class="root container">
  <div class="root header">header</div>
  <div class="root content">
    <div class="sub container">
      <div class="sub header">menu</div>
      <div class="sub content">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
        </ul>
      </div>
    </div>
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Michele Mariotti
  • 7,372
  • 5
  • 41
  • 73

2 Answers2

3

Your code is working as expected when setting the big height because max-height:100% in the child element need a reference, if you remove the height the max-height will fail to auto. As a side note, Firefox will have the same output even if you remove max-height so the issue isn't related to max-height. 1

Instead, you can keep the cascading flex container and rely on the default stretch alignment to obtain what you want:

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

* {
  box-sizing: border-box;
}

div {
  padding: 10px;
}

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

.content {
  flex: 1;
  max-height: 100%;
  overflow: auto;
}

.root.container {
  background-color: red;
  max-height: 100%;
}

.sub.container {
  background-color: purple;
  width:100%; /*added this*/
}

.root.header {
  background-color: lightblue;
}

.sub.header {
  background-color: lightgreen;
}

.root.content {
  background-color: yellow;
  display:flex; /*added this*/
}

.sub.content {
  background-color: orange;
}
<div class="root container">
  <div class="root header">header</div>
  <div class="root content">
    <div class="sub container">
      <div class="sub header">menu</div>
      <div class="sub content">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
        </ul>
      </div>
    </div>
  </div>
</div>

To better see the issue let's remove some properties and keep only the needed ones that will trigger the different behavior:

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

* {
  box-sizing: border-box;
}

div {
  padding: 10px;
}

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

.content {
  flex: 1;
  overflow: auto;
}

.root.container {
  background-color: red;
  max-height: 100%;
}

.sub.container {
  background-color: purple;
  height: 100%;
}


.root.header {
  background-color: lightblue;
}

.sub.header {
  background-color: lightgreen;
}

.root.content {
  background-color: yellow;
}

.sub.content {
  background-color: orange;
}
<div class="root container">
  <div class="root header">header</div>
  <div class="root content">
    <div class="sub container">
      <div class="sub header">menu</div>
      <div class="sub content">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
        </ul>
      </div>
    </div>
  </div>
</div>

All the issue is related to the inner height:100% used on the .sub.container. Technically and considering the specification this height should fail to auto because the parent height isn't set BUT Firefox seems to be able to evalute this height. Probably due to the nested flex container where we can evaluate the parent height before knowing the content or simply a bug.

Chrome is not doing this and simply ignoring the height which is the logical behavior.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • hmm that sounds right, but why the different behavior between Chrome and FF? Who is right? – Michele Mariotti Mar 13 '19 at 14:07
  • @MicheleMariotti I vote for chrome, because there is a violation in FF (I will edit my answer) but it's difficult to say. – Temani Afif Mar 13 '19 at 14:14
  • Actually, it seems that Chrome is using *declared* height as a reference, while FF is using *computed*. If you remove `height:100%` from `.sub.container` FF renders the same as Chrome. So, for FF that `100%` is a valid reference, for Chrome it is not. Even if the Chrome behavior seems more accurate, the FF one seems more useful. – Michele Mariotti Mar 13 '19 at 14:20
  • @MicheleMariotti exactly ;) I have also edited to show this ... FF is somehow doing a complex calculation (don't know exactly how) and this is the violation I am talking about – Temani Afif Mar 13 '19 at 14:27
1

Maybe height: fit-content is what you're looking for? I'm a little confused on what your desired result is.

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

* {
  box-sizing: border-box;
}

div {
  padding: 10px;
}

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

.content {
  flex: 1;
  max-height: 100%;
  overflow: auto;
}

.root.container {
  background-color: red;
  max-height: 100%;
  height: fit-content;
}

.sub.container {
  background-color: purple;
  height: 100%;
}

.root.header {
  background-color: lightblue;
}

.sub.header {
  background-color: lightgreen;
}

.root.content {
  background-color: yellow;
}

.sub.content {
  background-color: orange;
}
<div class="root container">
  <div class="root header">header</div>
  <div class="root content">
    <div class="sub container">
      <div class="sub header">menu</div>
      <div class="sub content">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          <li>Item 4</li>
          <li>Item 5</li>
        </ul>
      </div>
    </div>
  </div>
</div>
Jay
  • 353
  • 4
  • 8
  • The desired result is actually the result you see while running my snippet. Try to run your snippet on chrome to see the problem. `fit-content`, just as `auto`, is not working. – Michele Mariotti Mar 13 '19 at 13:07