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.
Justified and Vertically Centered Header with Pseudo-Elements

From our monthly sponsor: Create your beautiful portfolio website with Squarespace. Start your free trial.Advertisement

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!

Tagged with:

ML 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.

http://www.codrops.com

Receive our bi-weekly Collective or official newsletter right in your inbox.

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 75

Comments are closed.
  1. As someone who usually just keeps trying stuff until it works with CSS, this is rather useful!

  2. Thanks for the great walkthrough. I always look forwards to your contributions. Btw, very nice new profile pic too!

  3. Very useful article ML, Thank You.
    BTW you look more beautiful with new profil picture 😉

    • Obviously this won’t work on IE7 since it doesn’t support inline-block property. I haven’t tested this on IE8 but it should work. Btw Mary, thank you for the trick. This will be really useful.

    • As @Bobby pointed out, `inline-block` is not supported, per se. However, IE <=8 will treat any `display:inline` element like `display:inline-block` if `hasLayout` is triggered. So simply apply `zoom:1` or some similar `hasLayout` trigger and IE will let those inline elements behave just like inline-block.

      However, getting IE <=8 to handle inline-block is only half the problem, since IE <8 doesn't handle generated content. Thus, there's no way to force the left and right elements apart. Or is there?…

      IE 5.5+ supports `text-align-last` so setting that to `justify` will force even a single-line header to justify, even without the generated content hack. (see also my comment pointing this out)

  4. I am not one to comment on sites, actually this might be the first time, but this article saved the day. Sometimes for people at my level (3 years in) I might spend an entire day or more to fix some element that you just explained how to fix. Not sure if requests are ever taken but more article like this…centering, padding on responsive mobile flying invisible devices 🙂 you know what I mean? If someone told me years ago that a container inside a container makes it scalable I would have much more hair on my head. OK You are the best and I read and use everything you put out. keep up the great work. hope some of this made sense

    peace

  5. Great work as always, ML. This will be very useful in a current project. Thanks for sharing.

  6. This is great but I am still gob smacked at how something so simple to achieve can be so frustrating in css. Look at the steps you have to go through just to centre text. Coming from a print layout background who has moved in web i see it as a frustrating waste of time.

    But thanks for the solution.

    • Pinky I also came from a print background years ago, and used to carry the spitefulness towards coding, but once you wrap your head around CSS/HTML you learn to embrace tricks like this. Besides, print has similar little problems that can lead to hours of frustration, that is until you learn the tricks to solve them and move on with a smile 🙂

  7. I’ve been trying to find good ways to center my items in my headers, and this just helped me a lot! And it was simple too 😀 Thanks Mary!

  8. Great post, thank you Mary Lou! I never would have thought to use a pseudo element approach. I think I personally would have taken the display: table approach for this.

  9. This technique is in most circumstances just senseless. Prefering pseudo-elements to floatings is just more css typing and causes more rendering time and got no benefits at all. Just remove all pseudos, float those elements and check the line-heights. AAAAND that div wrapping the h1 is really really unnecessary.

    This article just shows how to make things more complicated and due to bad browser support of ::after in microsofts IE8….uh you know 🙂
    (IE8 only supports the single-colon CSS 2.1 syntax (i.e. pseudo-class). It does not support the double-colon CSS3 syntax (i.e. pseudo-element))

    Please be carefull with that.

    • Dom, I absolutely disagree with you. If you use floats, you need to clear them, line-heights won’t help you when text breaks and wrapping a div around a H1 is not overkill considering that you only need it if you define a fixed height for the header. This example is as simple as it can get and you can’t tell me that using floats will make this less complicated.

      And as I mention in the article: “If you’d like to support IE8, you should use “:” instead of “::” for the pseudo-elements.” It would be really nice if you read it and not just flew over it and comment 😉

      Please make a demo using floats and we can discuss it from there.

      Thanks for your feedback,
      ML

    • Dom, you’re not very experienced with responsive webdesign are you? She just solved a really common problem in a very clean way… :\

  10. Thanks Mary this is one way I would have never approached a situation like this… well until now! It still amazes me how many solutions there are to our everyday web problems.