3

In Google Chrome, how do I force an element nested inside of a member of a flexbox (by "member of a flexbox" I mean a child of an element styled with display:flex) to limit its size to the size of the flexbox member it's nested under? For example, suppose I have the following:

<div style="display:flex; flex-direction:column; height:100vh;">
  <div style="height:60px;">Static header</div>
  <div style="flex: 1 1 0; overflow:hidden;">
     <div style="overflow:auto; height:100%;" id="problem-is-here">
       Lots and lots of content, way too much to fit in the viewport
     </div>
  </div>
</div>

Because the first child div of the outermost div has a constant height, it ends up exactly 60px tall, and because the second child div has a flex-grow of 1, it gets the rest of the space available (in this case, 100% of the viewport minus 60px). I can confirm that this element's dimensions according to Inspect Element are just large enough to take up the rest of the viewport space.

In Firefox and IE11, due to the height:100%, the innermost element (id="problem-is-here") takes on the height computed for its parent. Therefore, since it is too small to display its content and overflow is set to auto, it (and not the entire body) gets a vertical scrollbar. This is what I want.

In Chrome, however, the innermost element is rendered with enough height to contain all of its content, which is a larger height than its parent. Thus, because its parent has overflow:hidden, no scrollbar appears and the excess content is inaccessible. How do I tell Chrome to render this innermost element with height at most equal to that of its parent, when the parent height is determined by a flexbox, not a CSS height property? Note that I can't give either the innermost div or its parent a definite height value since in the application I'm working on, the number of other flexbox members can vary.

Note: I have tried a few suggestions from other answers, such as setting all elements to have min-height:0 instead of auto, or ensuring flex-basis is set to 0, but none of these have worked. See

http://plnkr.co/edit/UBRcrNmR5iDbn3EXu6FI?p=preview

for an example that illustrates the problem. (The div with id heres-the-problem is the one whose height I want limited to the height of its parent.)

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Ajm Iam
  • 151
  • 1
  • 10
  • is this what you look for ? http://plnkr.co/edit/lxCkObgKgpEf0GYZbQtx?p=preview less markup and less css. HINT: margin reset for body – G-Cyrillus Nov 18 '15 at 20:34

1 Answers1

7

First, let's tackle the terminology:

...how do I force an element nested inside of a member of a flexbox (by "member of a flexbox" I mean a child of an element styled with display:flex) to limit its size to the size of the flexbox member it's nested under?

An element with display: flex is called a flex container (technically) or flex parent (colloquially).

The children of a flex container are called flex items. Note the word children (first-level). Descendents of a flex container beyond the children are not flex items and most flex properties don't apply to them.


Now, addressing your question:

The problem is that Firefox (and apparently IE11) have a different interpretation of the percentage height rule than Chrome.

Specifically, the vertical scrollbar you want is not rendering in Chrome because you're using percentage heights in a way that doesn't conform with the traditional implementation of the spec.

CSS height property

percentage
Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".

auto
The height depends on the values of other properties.

In other words, if you want an element to have a percentage height, then you must specify a height on the containing block (i.e. the parent).

In your code, body (level 1) has height: 100vh.

One level down, .max-flex (level 2) has height: 100%.

Four levels down, .large-nested-div (level 4) has height: 100%.

However, at .variable-flex-content (level 3), there is no height property. You are defining the height with flex: 1 1 0. As far as Chrome is concerned, this is a missing link in the chain and a violation of the spec. Chrome is expecting to see the height property, and when it doesn't, it computes the height to auto.


Chrome vs Firefox (I haven't tested IE11, so I won't mention it here)

Traditionally, when calculating percentage heights, browsers have interpreted the spec's use of the term "height" to mean the value of the height property. It could just as easily be interpreted as a height (generic term), but the height property requirement has become the predominant implementation. I've never seen min-height or max-height work on a parent when dealing with percentage heights.

Recently, however, as noted in this question and another one and another one, Firefox has broadened its interpretation to accept flex heights, as well.

It's not clear which browser is more compliant.

It doesn't help matters that the height property definition hasn't been updated since 1998 (CSS2).


The Solution

Instead of defining the height of .variable-flex-content with flex: 1 1 0%, try using height: 100% or height: calc(100% - 60px) or absolute positioning.

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Your suggestion of setting the `height` of `.variable-flex-content` would not work for me, as on the page I am working on, the total number of flex elements can change, and a static `height` would not work in all situations. However, setting `.variable-flex-content` to `position:relative` and setting its child to `position:absolute` caused `height:100%` to behave the way I wanted. See my updated plunk: [link](http://plnkr.co/edit/UBRcrNmR5iDbn3EXu6FI?p=preview). It produces the behavior I need as long as there is only one direct child of `.variable-flex-content`. – Ajm Iam Nov 19 '15 at 19:15
  • 1
    I figured as much. I was aware of the restriction from your question, but I included the `height` option anyway in case it became useful to you or others. My real solution for you was the absolute positioning. I was also going to suggest a nested flex box and `min-height` options, but didn't want the answer to get too long. I'm glad you got the issue resolved. Thanks for the feedback. – Michael Benjamin Nov 19 '15 at 19:19
  • More (and possibly better) solutions here: https://stackoverflow.com/q/33636796/3597276 – Michael Benjamin Sep 22 '17 at 14:09