Justified and Vertically Centered Header Elements

A little journey into positioning header elements to be centered vertically and justified with the help of pseudo-elements.

Header

Sometimes the most simple looking little layouts require complicated structures and various styling tricks. Centering elements, justifying content or aligning them the way we want can get really funky and frustrating. One of those little simple things that comes with many pitfall when laying it out is the justified header: title on the left and navigation on the right side. You could use floats, position one of the elements absolutely and more, no big deal. But now you’d like to center both things vertically. Easy, just add paddings, margins or set the line-height to the height of the parent, right? There are surely many solutions but when you start to think “responsively”, not all of these solution are so easy after all and they might bring some undesired effects. Especially the combination of both, vertical centering and justification, can get quite messy.

Today I don’t want to go through all of the different possibilities of centering header (or any other) elements vertically and justifying them. I just want to show you some simple CSS tricks that will do it right, in my opinion. Not much markup, no absolute elements and no floats. Just one magic word: pseudo-elements.

So, we want to create a header with the following look:

Header01

The markup is simply

<header>
	<h1>Super Bad</h1>
	<nav><a>First Link</a><a>Second Link</a><a>Third Link</a></nav>
</header>

We want the header to have a fixed height and some padding. It also needs a text-align: justify because we want to spread the children:

header {
    text-align: justify;
    letter-spacing: 1px;
    height: 8em;
    padding: 2em 10%;
    background: #2c3e50;
    color: #fff;
}

In order to spread the heading and the nav, we will first set them both to inline-block. Like that we can put them next to each other without using floats or absolute positioning.

header h1,
header nav {
    display: inline-block;
}

But for the text-align: justify to work as we wish (setting the heading on the left and the nav on the right), we need to use a little pseudo-element trick that I’ve found in this great article by Jelmer de Maat. Justifying inline or inline-block elements only works if their length is actually bigger than the one of their container, i.e. once we have an overflow or line-break. But since this is not the case here, the content is not justified. Here we will leverage the power of pseudo-elements: we can give the pseudo-class ::after a width of 100% and set it to inline-block. This will cause a line-break and our content will get justified like we wanted:

header::after {
    content: '';
    display: inline-block;
    width: 100%;
}

So this it what we have right now:

JS Bin

Nice, we’ve positioned both elements horizontally as we wanted without using floats or absolute positioning. But now we’d also like to center them vertically. I can hear your alarm bells going off, you’ve surely fought with this many times: vertical centering. There are many attempts and solutions but they all come with some downsides or just seem too complicated. At this point, you might think about margins, line-height and of course absolute positioning.

Let’s try to find a better way.

If you play around with vertical-align on the nav, you will notice that it will move vertically relative to the height of the heading. For example, let’s try vertical-align: top:

JS Bin

As you can see, the nav moves up.

If we set the height of the heading to 100%, we can center the nav relative to the header height by setting vertical-align: middle:

JS Bin

Now, how can we make both elements be centered inside of the header container? We would need another element that would make the vertical-align work as we want. I can hear you thinking now… Maybe a pseudo-element? Yes, of course! Again, we will use a pseudo-element to create the desired environment for our properties to work, a technique by Michał Czernow mentioned in the article Centering the Unknown. So, we will add a pseudo element that has a height of 100% and a vertical-align of middle:

header h1 {
    height: 100%;
}

header h1::before {
    content: '';
    display: inline-block;
    vertical-align: middle;  
    height: 100%;
}

And as a result we get what we want:

JS Bin

Almost! It does look right, but we need to make sure of two more things:

  1. line-breaks for longer text
  2. responsiveness

So, let’s start with number one. If our title would be much longer, our pseudo-element would cause an undesired effect which is to push the heading from the second line on down. That’s of course logical since we have a pseudo-element with a height of 100%:

JS Bin

(Note that we’ve, of course, restricted the width of the h1 to 50% because we don’t want it to just fill all the header.)

Let’s fix that by wrapping the heading into another division…

<header>
	<div><h1>Super Bad</h1></div>
	<nav><a>First Link</a><a>Second Link</a><a>Third Link</a></nav>
</header>

…and using the pseudo-element trick on that element:

header {
    text-align: justify;
    height: 15em;
    padding: 2em 5%;
    background: #2c3e50;
    color: #fff;
}

header::after {
    content: '';
    display: inline-block;
    width: 100%;
}

header > div,
header nav,
header div h1 {
    display: inline-block;
    vertical-align: middle;
}

header > div {
    width: 50%;
    height: 100%;
    text-align: left;
}

header > div::before {
    content: '';
    display: inline-block;  
    vertical-align: middle;
    height: 100%;
}

And we get this:

JS Bin

Number one is off the list, so let’s take care of the responsiveness. There are of course, several possibilites when it comes to flexible layouts. You could for example, not define a height for the header at all and let the inner elements and the padding be responsible for the height. In that case we also won’t need the second pseudo-element trick (and the wrapper for the h1) and we would simply have:

header {
    text-align: justify;
    padding: 2em 5%;
    background: #2c3e50;
    color: #fff;
}

header::after {
    content: '';
    display: inline-block;
    width: 100%;
}

header h1,
header nav {
    display: inline-block;
    vertical-align: middle;
}

header h1 {
    width: 50%;
    text-align: left;
    padding-top: 0.5em;
}

header nav {
    padding-top: 1em;
}

Which looks like this:

JS Bin

This will adjust just fine on smaller screens. But if you need a defined height (for example, just think about a full window height header) then we need our second pseudo-element trick, the wrapper and a media query that will simply take care of the smaller screens and maybe center the elements:

@media screen and (max-width: 820px){
    
    header {
        height: auto;
    }
    
    header > div,
    header > div h1,
    header nav {
        height: auto;
        width: auto;
        display: block;
        text-align: center;
    }
    
}

With the following result:

JS Bin

Note that I’m using 820px here because I want to show you what happens beyond that breakpoint. You should of course use an appropriate value for your layout.

If you’d like to support IE8, you should use “:” instead of “::” for the pseudo-elements.

Let’s give this baby some love and finalize the style:

@import url(http://fonts.googleapis.com/css?family=Lato:400,700italic);
* { padding: 0; margin: 0; }
body { background: #1abc9c; font-family: 'Lato', sans-serif; text-transform: uppercase; letter-spacing: 1px;}

header {
    text-align: justify;
    height: 8em;
    padding: 2em 5%;
    background: #2c3e50;
    color: #fff;
}

header::after {
    content: '';
    display: inline-block;
    width: 100%;
}

header > div,
header > div::before,
header nav,
header > div h1 {
    display: inline-block;
    vertical-align: middle;
    text-align: left;
}

header > div {
    height: 100%;
}

header > div::before {
    content: '';
    height: 100%;
}

header > div h1 {
    font-size: 3em;
    font-style: italic;
}

header nav a {
    padding: 0 0.6em;
    white-space: nowrap;
}

header nav a:last-child {
    padding-right: 0;
}

@media screen and (max-width: 720px){
    
    header {
        height: auto;
    }
    
    header > div,
    header > div h1,
    header nav {
        height: auto;
        width: auto;
        display: block;
        text-align: center;
    }
    
}

And here we go:

JS Bin

And that’s it! We’ve centered the elements vertically and aligned them as we wanted.

This is of course just one way to do it and there are surely tons of possibilities. I just found this one to be really neat.

Hope this was somehow useful to you!

Previous:
Next:

Tagged with:

Mary Lou (Manoela Ilic) is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by

Website: http://tympanus.net/

Related Articles

Feedback 68

  1. 1

    Hi Mary, I loved this tutorial. The code stays clean and beautiful.
    I would only suggest you to use an <hgroup> instead of a <div> for more semantic purposes.

    ;)

    • 2

      @Habner It was mentioned already, but has been deprecated for a few months now. With all these new tag elements, you should be checking the specs often to make sure they are still valid.

  2. 4

    Hi, this is an awesome technique, but I just spent like 2 hours trying to get this to work.

    The problem I had is that you need white space between the interior elements for text-align: justify to work. Not whitespace that you have explicitly defined, but whitespace in the actual markup.

    This works:

    <header>
    <div><h1>Super Bad</h1></div>
    <nav>
    <a>First Link</a>
    <a>Second Link</a>
    <a>Third Link</a>
    </nav>
    </header>

    This doesn’t
    <header><div><h1>Super Bad</h1></div><nav><a>First Link</a><a>Second Link</a><a>Third Link</a></nav></header>

    I am using a web framework that concatenates the HTML generated from its templating language onto one line (to save space i guess?). This resulted in this trick not working. While I can change this, it seems really really risky to have the entire layout of an important part of your site depending on the unrelated internals of your server.

    Please warn people in your tutorial, so that nobody else suffers a similar fate.

    • 5

      Just a follow up, was able to solve this problem in what I hope is a solid way: by putting an &nbsp; between the elements, I was able to explicitly define the whitespace required.

  3. 7

    Hi, I’ve tried this code

    header {
    background: #2c3e50;
    color: #fff;
    padding: 2em 10%;
    letter-spacing: 1px;
    height: 8em;
    text-align: justify;
    }
    header h1, header nav {
    display: inline-block;
    }
    header::after, header::before {
    content: '';
    display: inline-block;
    width: 100%;
    background: black;
    }

    And I get justified and vertically centered effect.
    Could this code become alternative?

  4. 8

    hi, Mary i love this tutorial. i am still learning web designing ,and there are somethings i would like to ask you . looked for you on Facebook but i couldn’t find you, please how do i contact you thanks .

  5. 9

    This is simple but not so simple …
    Many frontends frameworks included an header, but resizing it need to change many css lines.
    Here : everything is verticaly and horizontaly in place and you just need to change 1 value to height it.
    It’s sure now I’m a noob :o) Bravo!
    Note : next step : codrops framework ? Everything is here …

Follow this discussion

Leave a Comment

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>