Boxes That Fill Height (Or More) (and Don’t Squish)

Chris Coyier //

It's hard to sum up all the awesome that is flexbox in a little ol' blog post. Although we gave it a shot here. Here, let's just try and focus on one thing that flexbox solves very nicely: the ability to have an arbitrary set of boxes fill up all the available height of a parent box. And not only that, but expand beyond that if needed (not squish them to fit).

By "box", I just mean block level element. Div, section, article, whatever.

By default those boxes height is determined by the content inside them. They will stack on top of each other. Their parent boxes height might also be determined by their height combined, but it could be different (e.g. it's set explicitly or it's something variable like the browser window). If the parent box has a larger height, there will just be empty space below.

Can't we force the boxes to split up the space evenly amongst that space? We can with flexbox.

Left: default; Right: what we wanna do

Say the HTML is like:

<section class="fill-height-or-more">
  <div>
    <!-- stuff -->
  </div>
  <div>
    <!-- stuff -->
  </div>
  <div>
    <!-- stuff -->
  </div>
</section>

Then we kick off flexbox with the parent box:

.fill-height-or-more {
  display: flex;
}

and make the boxes up-and-down (column) rather than left-and-right (row) as is the default:

.fill-height-or-more {
  display: flex;
  flex-direction: column;
}

With just that, it will look no different than it did if we did nothing. But now we apply the flex property to the children and they will fill the space:

.fill-height-or-more > div {
  /* these are the flex items */
  flex: 1;
}

Annnnd done =).

As a detail here, flex: 1; is the same as saying flex: 1 1 auto; It is shorthand for three different properties:

flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

Just so happens that giving them the ability to grow on an equal basis the most common need so flex: 1; is a nice way to write that.

One of the nice things about flexbox is this will work with an arbitrary number of boxes. Could be a single box! Could be 100 boxes! Doesn't matter. If there is extra room, the space will be divided and filled. If not, no big deal.

In a pre-flexbox world, we might have tried to know/find out how many boxes there were, and then set their heights with percentages. That works to fill extra space, but if there were too many boxes, you'd get squished. That's another nice thing about flexbox, it won't squish those boxes to the point of them not being able to fit their content. So...

Left: if we were to use percentages; Right: Normal desired behavior

If we wanted to take this a step further, we could use flexbox to center the content within those boxes too (!). This is where people get mad at CSS though. Vertical centering is kinda hard. Even with flexbox here, we'll need to make each of those flex item children we have into flex containers as well. Then use an internal wrapper which becomes the flex item we center. So yeah, an extra element still. Update: Tedmotu did it without the extra element, which is really straightforward

To center it, we make the direction up-and-down again (column) and use another flexbox property, justify-content, to center it.

.fill-height-or-more > div {
  flex: 1;

  display: flex
  justify-content: center;
  flex-direction: column;
}

This is where the reference guide comes in handy... finding out which property does what quickly.

Then we get this:

See the Pen Boxes That Fill Height (or more) by Chris Coyier (@chriscoyier) on CodePen.

Browser Support

I've only used the latest syntax here in this post. Current versions of Chrome, Opera support it just like that. Near-future versions of Firefox and Android will be supporting it just like that as well. Safari and iOS support the new syntax, just with -webkit- prefixes. Can I Use has the whole story.

IE is weird. IE 10 supports the tweener version of flexbox (e.g. display: -ms-flexbox;). IE 11 supports the latest flexbox. With this particular demo though, something is broken. While the height of .fill-height-or-more renders at full height by using min-height, the boxes are squished.

If you use height instead of the flex container, it "works" - but the point here was using min-height to avoid squishing. Seems like an implementation bug to me.

It's understandable that you might need to go back a bit further with browser support. Firefox 27, iOS 6, and Safari 6 are pretty legit browser support targets and all those use some variation of the older syntax, sometimes prefixed and sometimes not.

Just our little example looks like this when as fleshed out as it can be for support:

.fill-height-or-more {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
} 

.fill-height-or-more > div {
  -webkit-box-flex: 1;
  -webkit-flex: 1;
  -moz-box-flex: 1;
  -ms-flex: 1;
  flex: 1;
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -moz-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}

Yeesh. My recommendation? Write it in the modern syntax like I have above and let Autoprefixer deal with it, which not only deals with the prefixing but the older syntax as well.

Video Screencast

Might as well hey? I published it here and I'll embed it also:


Oh and just for the record, the real-world scenario that brought this on for me was this page.