27

I have a app that uses a classic email like layout like the one below.

I have constructed it using the new CSS3 flexbox model and it works brilliantly until I add the ability for the user to dynamically add new items in the folders box. I would have hoped that flexbox worked in such a way that as long as there is space left in the folders box it would not begin growing into the tasks box underneath. Unfortunately this is not what I am seeing (in Chrome 17).

I have constructed a JSFiddle here that demonstrates the problem. Just click the Add Folder link and you will see the folders box growing, even though it has space enough left to accommodate the new child.

To the question. How can I construct two vertically aligned boxes using flexbox in such a way that one takes up two thirds of the available height (box-flex 2) and the other one third (box-flex 1) and that they do it in such a way that when new content is added to the first box it does not begin growing until it is out of space.

Lars Tackmann
  • 20,275
  • 13
  • 66
  • 83
  • 1
    Actually, that is how it is supposed to behave. If A has `box-flex: 2` and B has `box-flex: 1`, that doesn't mean that A will be twice as big as B. It means that A will take twice as much leftover space as B. If there's 90px of left over space, A will take 60px and B will take 30px. The bigger A and/or B are, the less space there is to split between the two. The newer spec addresses this by allowing you to specify its ability to grow independently from its ability to shrink. – cimmanon Feb 19 '13 at 18:06

3 Answers3

16

I can't say for sure if that's a browser bug or if it is in fact how the flex model is supposed to work. If that is how it should work I'd agree that's not exactly intuitive!

I found a work around by wrapping the lists in an absolutely positioned div with the overflow set to auto. This allows the flex boxes to maintain their original states and only change when the entire layout is recalculated vs. the content changing.

Here's the updated markup:

<section id="folders">
   <div class="dynamicList">
   <h2>Folders</h2> 
   <ul>
      <li>Folder 1</li>
      <li>Folder 2</li>
   </ul> 
   <a href="#" id="add">Add Folder</a>
   </div>      
</section>

And the updated CSS:

#left #tasks,
#left #folders {
  position: relative;
}

.dynamicList {
  bottom: 0;
  left: 0;
  overflow: auto;
  position: absolute;
  right: 0;
  top: 0;
}

I forked your fiddle here to demo: http://jsfiddle.net/MUWhy/4/

UPDATE:

If you want the headings to remain fixed and only have the contents of the folder and tasks lists scroll, then I would consider putting the headings and the add buttons in their own fixed-height boxes within the #left div. It's a bit more mark up but still pretty simple. I haven't tried it on JSFiddle but I think that would be the best route to go.

Jim Jeffers
  • 17,572
  • 4
  • 41
  • 49
  • Spot on, this solved it exactly like I wanted it. Although I am still left with a feeling that its either a bug in Chrome's Flexbox handling or that I somehow don't understand some of the more advanced flexbox features (as demonstrated here http://www.the-haystack.com/2012/01/04/learn-you-a-flexbox ) – Lars Tackmann Feb 12 '12 at 20:40
  • Haha, I needed exactly that, and it turns out this solved my root-cause for switching from tables to the flex layout. It is still only 2013, back to tables again. Thank you. – zupa Apr 10 '13 at 07:41
14

I have got this answer from my other question which is is the same more or less: https://stackoverflow.com/a/14964944/1604261

Instead of @LukeGT solution, that it is a workaround and not the solution to obtain the effect, you can apply a height to the element where you want to see a vertical scroll.

So the best solution if you want a min-height in the vertical scroll:

#container article {
    -webkit-flex: 1 1 auto;
    overflow-y: auto;
    min-height: 100px;
}

If you just want full vertical scroll in case there is not enough space to see the article:

#container article {
    -webkit-flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0px; /* or height:0px */
}

If you do not set the height (using height or min-height) the vertical scroll will not be set. In all cases, even with height: 0px; the calculated height of the element will be different to zero.

My solution with -webkit prefix: http://jsfiddle.net/ch7n6/4/

Edit:

Since Firefox now supports full flexbox specification, removing -webkit- vendor prefix it will work with all browsers.

Community
  • 1
  • 1
José Cabo
  • 6,149
  • 3
  • 28
  • 39
4

I prefer this solution to Jim's since it's less of a hack - it will work on any flexbox on any part of the page. Jim's can only work on a box in the very top left of a page.

I solved this by wrapping the part of the flex box that I wanted to scroll inside a div.scrollbox. I made the direct children of this div have a height of 0, so that adding extra elements within it would not affect the rest of the layout. I also set its overflow-y to auto so that a scrollbar would appear if its children extend beyond its bounds.

.scrollbox {
    -webkit-flex: 1 1 auto;
    overflow-y: auto;
}
.scrollbox > * {
    height: 0;
}

Note that this will only work if the extendible content is placed within a containing element or containing elements. In this example, li elements are contained within a containing ul element, so it works.

I also had to make some changes in order to get the 3 components of the top left flexbox to arrange themselves properly, but this was application specific.

#folders {
    display: -webkit-flex;
    -webkit-flex-flow: column;
}
#folders h2, #folders #add {
    -webkit-flex: 0 1 auto;
}

I forked the above jsfiddle here: http://jsfiddle.net/FfZFG/.

LukeGT
  • 2,324
  • 1
  • 21
  • 20