Andrew Que Sites list Photos
Projects Contact
Main

November 04, 2019

A Flexbox Example

At work this week I had to implement some CSS Flexible Boxes (flexbox), and I'm getting better at using them. The layout called for a fixed- height title bar, fixed-height lower bar with a variable height middle. And in the middle, a fixed-width left and right bar with a variable middle. This illustrates the layout I'm looking for:

Top
Left
Middle
Right
Bottom

The goal here is to have the middle box adjust to the remaining space available. CSS flexboxes are exactly what is needed, but they can be a little tricky to setup. The important thing to remember is that for a <div> to be flexible, it's parent must be marked as flex. The children then need to either specify their size, or be told to stretch. Let's start with a stripped down version of what is need. In this example, we need one fixed-sized <div> on the left, and a variable size <div> on the right that will take the remaining space.

Left
Right

Here is the code to accomplish this :

.body
{
  flex-direction: row;
  width: 400px;
  height: 50px;
  padding: 2px;
}

.left
{
  padding: 2px;
  margin-right: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

.right
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;
}

<div class="body">
  <div class="left">Left</div>
  <div class="right">Right</div>
</div>



Note that we can add boxes to the right and the center will still take the remaining space.

Left
Center
Right 1
Right 2
.body
{
  flex-direction: row;
  width: 400px;
  height: 50px;
  padding: 2px;
}

.left
{
  padding: 2px;
  margin-right: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

.center
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;
}

.right
{
  padding: 2px;
  margin-left: 2px;
  width: 50px;
  background-color: #A0A0A080;
}



<div class="body">
  <div class="left">Left</div>
  <div class="center">Center</div>
  <div class="right">Right 1</div>
  <div class="right">Right 2</div>
</div>

This takes care of the center portion of our request. Now about adding the top and bottom. Let's make a simple change to our setup so this is column based rather than row.

Top
Center
Bottom
.body
{
  flex-direction: column;
  width: 400px;
  height: 150px;
  padding: 2px;
}

.top
{
  padding: 2px;
  margin-bottom: 2px;
  height: 25px;
  background-color: #A0A0A080;
}

.center
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;
}

.bottom
{
  padding: 2px;
  margin-top: 2px;
  height: 25px;
  background-color: #A0A0A080;
}



<div class="body">
  <div class="top">Top</div>
  <div class="center">Center</div>
  <div class="bottom">Bottom</div>
</div>

Now we combine the two setups, nesting the column-based set in the row- based set.

Top
Left
Middle
Right
Bottom
.body
{
  flex-direction: column;
  width: 400px;
  height: 150px;
  padding: 2px;
}

.top
{
  padding: 2px;
  margin-bottom: 2px;
  height: 25px;
  background-color: #A0A0A080;
}

.middle
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;

  display: flex;
  flex-direction: row;
  padding: 4px;
  width: calc( 100% - 8px );
}

.bottom
{
  padding: 2px;
  margin-top: 2px;
  height: 25px;
  background-color: #A0A0A080;
}

.middleLeft
{
  padding: 2px;
  margin-right: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

.middleCenter
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;
}

.middleRight
{
  padding: 2px;
  margin-left: 2px;
  width: 50px;
  background-color: #A0A0A080;
}



<div class="body">
  <div class="top">Top</div>
  
  <div class="middle">
    <div class="middleLeft">Left</div>
    <div class="middleCenter">Middle</div>
    <div class="middleRight">Right</div>
  </div>
  
  <div class="bottom">Bottom</div>
</div>

A couple of items to note. We have two flexible parents, the outer body div, and the middle div. The middle div can both grow and is a flex parent. The middle also uses a bit of math on the width to account for the padding. It should take 100% of the cell, but account for the 8 pixels of padding, 4 on the left, and 4 on the right.

Let's allow the flex area to be resized. Try changing the size by dragging the bottom left corner around.

Top
Left
Middle
Right
Bottom

So it would appear we are done, however there is just one problem.

Top
Left
  • Value A
  • Value B
  • Value C
  • Value D
Bottom

The problem here may not be immediately obvious, but the right column has been shrunk. This happens because the content of the middle div is large and the left and right divs are allowed to shrink. However, we can prevent that.

Top
Left
  • Value A
  • Value B
  • Value C
  • Value D
Bottom
.top
{
  padding: 2px;
  margin-bottom: 2px;
  height: 25px;
  background-color: #A0A0A080;
  flex-shrink: 0;
}

.middle
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;

  display: flex;
  flex-direction: row;
  padding: 4px;
  width: calc( 100% - 8px );
}

.bottom
{
  flex-shrink: 0;
  padding: 2px;
  margin-top: 2px;
  height: 25px;
  background-color: #A0A0A080;
}

.middleLeft
{
  flex-shrink: 0;
  padding: 2px;
  margin-right: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

.middleCenter
{
  padding: 2px;
  flex-grow : 1;
  flex-shrink: 1;
  background-color: #A0A0A080;
}

.middleRight
{
  flex-shrink: 0;
  padding: 2px;
  margin-left: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

While that fixes the column width, it is easy to see that there is a problem with overflow. To fix this we need to address overflow in two location: the middle parent div, and the middle child. The parent can be marked to hide overflow, and the child can either hide or use scroll bars.

Top
Left
  • Value A
  • Value B
  • Value C
  • Value D
Bottom
.top
{
  padding: 2px;
  margin-bottom: 2px;
  height: 25px;
  background-color: #A0A0A080;
  flex-shrink: 0;
}

.middle
{
  padding: 2px;
  flex-grow : 1;
  background-color: #A0A0A080;

  display: flex;
  flex-direction: row;
  padding: 4px;
  width: calc( 100% - 8px );
  overflow: hidden;
}

.bottom
{
  flex-shrink: 0;
  padding: 2px;
  margin-top: 2px;
  height: 25px;
  background-color: #A0A0A080;
}

.middleLeft
{
  flex-shrink: 0;
  padding: 2px;
  margin-right: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

.middleCenter
{
  padding: 2px;
  flex-grow : 1;
  flex-shrink: 1;
  background-color: #A0A0A080;
  
  overflow: auto;
}

.middleRight
{
  flex-shrink: 0;
  padding: 2px;
  margin-left: 2px;
  width: 50px;
  background-color: #A0A0A080;
}

When all of this is done we can get a complex layout that sizes how we want. With the demo below try resizing the content to see how the layout allows the middle box to take the remaining room.

Title of Fixed Area

  • Value A
  • Value B
  • Value C
  • Value D
  • Value E
  • Value F
  • Value G
  • Value H
  • Value I
  • Value J
  • Value K
  • Value L
  • Value M
  • Value N
  • Value O
  • Value P
  • Value Q
  • Value R
  • Value S
  • Value T
  • Value U
  • Value V
  • Value W
  • Value X
  • Value Y
  • Value Z
Column A Column B Column C Column D
Value AValue BValue CValue D
Value AValue BValue CValue D
Value AValue BValue CValue D
Value AValue BValue CValue D
A C D

There you have it. I find it helps to build a page layout in steps so you can get the complexities of items such as flex boxes and overflows.

   I'm sure part of the allure of setting up a haunted house each year is that same feeling you get when completing a set for a play.  And just like when the play is over, once you strike the set the finality of the end sinks in.  It is always sad to see the end of hard work, but as soon as it is over the yearning to do it again takes hold.