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.
   Xiphos' dragon turned out great.  He some hardware to hold the head up using one of his light stands and counter weighted the jaw.  Then he added his geyser fog machine and the results turned a lot of heads.  I'm going to look into getting some strong stepper motors to see if we can't animate the jaw and head.

   The Halloween garage tour this year was my largest yet.  It was divided into 5 areas: Old Sparky (the Electric Chair), Black Widows Nest, The Alchemist's Workshop, the Hall of Terror, and the Mad Scientist's Laboratory.  I had intended to add the Werewolf's Den but didn't get the sound trigger done in time.  Unlike in years past, this year was a full tour with separate rooms.  The first room has the creepy baby sitting with a severed limp and a blood axe as well as Old Sparky.  I had wanted to shake the electric char using a motor spinning a block of wood.  While I had such a setup working the mount used the hold the motor in place wasn't good enough and the motor kept coming loss.  So for safety reasons I didn't include it. 
   The next room had two scenes: The Alchemist's Workshop and the Black Widows Nest.  The Black Widows Nest is completely new and consisted of two spider webs, a very large spider, and a pile of bones.  The webs I picked up were not quite as large as I'd hoped but functioned.  One was white, the other black.  Since a black web didn't make sense, I used it as kind of a shadow to look through into the rest of the scene.  The bones started with a set of plastic bones but they didn't look that good.  Zach had been using a pressure cooker with read pork bones and I used them after he was done.  They looked great and I think I will collect some more actual bones for future setups.
   The Alchemist's Workshop this year was much larger.  It contained some bubbling experiments but this year I picked up a very powerful aquarium pump so I didn't have to use the air compressor.  That worked out better since last year the compressor tripped the breaker.  Rather than fill all the jars with colored water I picked items we had laying around: oatmeal, rice, sugar, popcorn; and augmented it with clippings I took form random plants outside.  About half the jars were empty and I might have to figure out some better items to use in the future.  A couple of new items included flickering LED candles made with actual wax, and a hanging cauldron.  I had wanted to have the cauldron to use piezoelectric fog devices so that it steamed, but the ones I ordered didn't come with power supplies and were left out.  For the desk I used an old table but it didn't look right so I covered the table with two 2x12 planks that had been left outside for a couple years.  This gave it the weathered look I was after.
   The next section was the Hall of Terror.  It started with a hanging body prop.  I had wanted to put the body right in the middle of the path so you had to push past it, but the hanging canvas that made the path didn't make that work.  Then a strobe light illuminated by big (not so) scary face.  That was supposed to be a distraction from the large mirror you had to walk past.  The mirror was a simple one-way film with someone (Zach mostly) standing behind it in a scary mask.  From the back side of the mirror you could see very clearly people approaching.  Those approaching could not see anything but a reflection.  That is until the person behind the mirror turned on a flash light illuminating their face.  It had the desired effect and was one of the scariest things in the setup.  The only thing about the hall that could have been better was the strobe light.  It is a true xenon strobe tube, but very weak.  I had to have some light to illuminate the floor and the hall didn't have the stop-motion I had hoped for.  I'll need a bigger strobe light next year.
   The last and largest area was the mad scientist's laboratory.  It had the Jacobs Ladder, a haze machine, several lasers, and the monster on the slab.  It was designed to be the least scary part of the walk through so that little kids could skip most of the setup and just see the lab.
   We had a lot of people come through, including many who had come the previous year.  We went through 4 large bags of candy (I picked up 5 total) despite the temperatures being around freezing.  The two-way mirror got the most scares and I will be using that again.  Overall I am pleased with how it turned out.  I put a lot of hours in this year's setup, and a lot more money, but I think the worked paid off.  I'm not sure how I am going to top it next year, but that's a problem for next year!
   The finished mask for my Halloween costume.  It is off-the-shelve except for the eyes.  Nothing covered the eyes and it took away from the effect.  So I picked up some black nylon stocking and used them to cover the eyes.  Initially I tried rubber bands and glue to hold the eye covers in place, but neither worked.  So I used a couple of tacks.  This had the added effect of metal spikes sticking out of the sides of the eyes.  I can still see through the nylon and my eyes are much less visible, producing the desired effect.  Together with a balaclava, a grim ripper's robe, and some lighted gloves my costume for tomorrow is complete.