Melinda McCaw Media(720) 935-3715
Melinda McCaw Media

Flexbox Part 3 – Centering

Wednesday, July, 26th, 2017 at 6:00 am by Ernie Ripley

Part three of the series is about centering a child within a parent element. This sort of thing is useful if, say, you have a menu along the top and then a hero image with some text centered within the hero. In this particular situation we want the whole menu/hero element to span the height of the users screen (100 vh).

The Problem:

In this case the problem isn’t a complicated one. Centering an element can already be achieved fairly simply without flexbox. However the faster I can code and move on, plus the less likely errors in css, the better.

To do this without flexbox we might have a container with two child elements I usually call banner, for the menu, and hero for the image. I would give the banner a set height of 15vh and hero a set height of 85vh. This would make the container 100vh. Then to center the text in the hero I would position the text absolutely within the relative hero with a top:50%; and a left:50%;. This will make the text a little off center so to bring it back I would use a transform: translate(-50%, -50%); -webkit-translate(-50%, -50%); -moz-translate(-50%, -50%); -ms-translate(-50%, -50%);.

This works perfectly, but there are some drawbacks. If you ever needed to edit this a year later you may forget all about the transform you did on the text and overwrite it with a new transfrom like scale or something. A minor issue but still can be frusterating. Also you must carry around all those vendor prefixes with you… not desireable. Over all it’s just more complicated and error prone than the flexbox way.

The Solution:

Flexbox offers a very quick and easy way to get this done, and without vendor prefixes being required on the child element. Before we get to the centering part lets get the container and the banner set up. We will use flexbox for this as well so that the height of the banner can be dynamic. We will also just use the menu from Part 2 of this series to put in our banner.

Lets start with the html, a simple container div with two child divs… banner and hero:

<div class="container">
  <div class="banner">
  </div>
  <div class="hero">
  </div>
</div>

Then lets throw the menu we created in Part 2 into the banner:

<div class="container">
 <div class="banner">
   <ul>
     <li><a href="#">Lorem ipsum</a></li>
     <li><a href="#">dolor</a></li>
     <li><a href="#">sit amet</a></li>
     <li><a href="#">consectetur adipiscing elit</a></li>
     <li><a href="#">Suspendisse vel</a></li>
     <li><a href="#">eleifend nibh</a></li>
     <li><a href="#">Sed placerat</a></li>
     <li><a href="#">mi vitae tincidunt</a></li>
   </ul>
 </div>
 <div class="hero">
 </div>
</div>

I also want to add the styles from that menu into our stylesheet:

@import url('https://fonts.googleapis.com/css?family=Bubbler+One');
*{
 box-sizing: border-box;
}
body{
 margin: 0;
}
ul{
 margin: 0;
 padding: 0;
 display: flex;
}
li{
 list-style: none;
 flex-grow: 1;
}
li a{
 text-decoration: none;
 text-align: center;
 background-color: #444;
 display: block;
 color: #fff;
 text-transform: lowercase;
 font: 700 24px/3em 'Bubbler One', sans-serif;
}
li a:hover{
 background-color: #222;
}

From this point our website looks like this:

Now lets work on the hero. Bonus! We are actually going to solve another common problem. How do we fill the remaining space of a container without knowing the dimensions of the other elements. With flexbox we can dynamically fill the remaining space with the hero regardless of the height of the banner. Keep in mind that we want our container to be 100vh (the height of the screen).

To do this I am going to add display:flex; to the container. I also want to change the direction that flexbox works with the children of the container so I am going to add flex-direction: column;.  This way I can use flexbox in a vertical direction. Now to make the hero use up the rest of the 100vh that the banner does not use I just set hero to flex-grow: 1; and we get a perfect banner/hero container that is 100vh tall without having to know how tall the banner is.

The added css:

.container{
 display: flex;
 flex-direction: column;
 height: 100vh;
}
.hero{
 background-image: url(https://upload.wikimedia.org/wikipedia/commons/f/f4/Fall-foliage-forest-creek-scenery-sunset_-_West_Virginia_-_ForestWander.jpg);
 background-size: cover;
 flex-grow: 1;
}

The website:

Ok now lets get down to the task at hand. We need some text in the hero and we need it to be centered. To do this lets add the html for our text inside of banner like this:

<div class="text">
  <h1>Visit Melinda McCaw Media Now!</h1>
  <p>Melinda McCaw Media is the solution to all your website and graphic design needs</p>
</div>

Then we add some character to our text:

.text{
 color: #fff;
 font-family: 'Bubbler One', sans-serif;
 text-align: center;
 padding: 20px;
 width: 400px;
 background-color: rgba(0, 0, 0, .7);
 border-radius: 5px;
}
.text h1{
 text-transform: lowercase;
 font-weight: 700;
}
.text p{
 font-family: sans-serif;
 font-weight: 300;
}

This gives us a nice text box with a dark transparent background and white text but the text box is still in the upper left corner of the hero:

From here we could use absolute positioning and transform as mentioned above but we don’t like all that complicated css. Instead I will add display: flex; to the hero and then… margin: auto; to the .text class.

.hero{
 display: flex;
}
.text{
 margin: auto;
}

And that’s it we have successfully centered a text box within a parent div using flexbox. As a bonus we also made it so that the hero div dynamically fills the remaining space of the container who’s height we set to 100vh. Our result looks like this:

With that I am signing off, stay tuned for part four in this series, and if you haven’t done so check out parts 1 and 2 for more on how to leverage flexbox to make a better, more responsive web.