CSS Vertical Centering

Front-end developing is beautiful, and it's getting prettier by the day. Nowadays we got so many concepts, methodologies, good practices and whatnot to make our work stand out from the rest. Javascript (along with its countless third party libraries) and CSS have grown so big, helping us create things that even a couple of years ago were deemed impossible. But there's one thing that's often left in the dark, I'm sure you've stumbled with it at least once, and we know its fix is not always very good looking: vertically centering elements.

Now, there are many ways of addressing this issue: the table method, the height and half height method, the inserting-another-element-slash-pseudo-element-with-vertical-align-and-height-100% method, the calculate on load method, and more. Each of these seems dirtier than the last, it gets even more complicated when the element's height is unknown (be it a parent's or children's), and don't get me started on how bad it looks like when working with responsive layouts.

For a good time I went with the "calculate on load" method. The premise was simple: get the parent's height, subtract the children's height, divide by 2, and inline the top property with the result as a px value. Essentially, 50% of the parent's height - 50% of the children's height, done. Here's a visual representation of it:

Figure 1 - The red "210px" is the value we need to set on the "top" property.

And I know what you are thinking, "Inlining CSS is bad!!!", but this was the least ugly solution. It didn't require to change any element's box model, waste its pseudo-elements, insert another element just for the sake of a fix, nor any other hackery. But as I said before, things got trickier when the element's dimensions were unknown.

Sure, you could get over this by using a script that runs after the window has loaded, or on window/object resize, and then recalculate the positions. But what if you've got hundreds of elements, each getting resized to fit their parents frames? The script will take a huge performance hit. And more importantly, why complicate things so much when there's a simple, pure CSS solution?

Sample HTML

This is a frequent case: a parent with children we desire to be vertically centered.

Enter CSS3 Transforms

One interesting thing about CSS transforms is that, when applying them with percentage values, they base that value on the dimensions of the element which they are being implemented on, as opposed to properties like top, right, bottom, left, margin, and padding, which only use the parent's dimensions (or in case of absolute positioning, which uses its closest relative parent).

Knowing this, we could apply the same "calculate on load" method's small equation, but now adapting it to just CSS. First, we move the element in question down to the middle of it's parent using top: 50%, then we pull it back up by half of said element, with transform: translateY(-50%). Of course, the element must be relative, absolute, or fixed. If we look back to Figure 1, this is exactly what we have achieved.

Finally, a few warnings: If you want to centralice a relative positioned element, its parent must have a height value, i.e., it won't work if said parent's height is set to auto. And of course, as most CSS3 features and properties, transforms don't work in IE 8 and earlier versions.

About Brian Gonzalez

Front-end developer and designer originated from a small and proud island in the Caribbean, Dominican Republic, who recently moved to the US in search of broadening it’s horizons as a web developer, push his career to new heights, and hopefully meet and work with great, passionate developers and designers along the way.
Currently a freelancer, started designing and mocking up websites in early 2011 while still in college, but later discovered that making design come to life, and creating great experiences for the end user was even more gratifying, so soon after he was building full, interactive sites along a small team of colleagues. Since then, has helped build and lead several web projects from the ground up, exceeding the client’s expectations on each of them, and delivering best in class user experience.
His interests include working on big and challenging projects, listening to loud, fast paced music, and eating inconsiderable amounts of asian food.

One of my favorite social APIs was the Open Graph API adopted by Facebook. Adding just a few META tags to each page allowed links to my article to be styled and presented the way I wanted them to, giving me a bit of control...

One event that's always been lacking within the document is a signal for when the user is looking at a given tab, or another tab. When does the user switch off our site to look at something else? When do they come back?

One technique I'm seeing more and more these days (CNNSI.com, for example) is AJAX recording of selected text. It makes sense -- if you detect users selecting the terms over and over again, you can probably assume your visitors are searching that term on Google...

The way that album information displays is usually insanely boring. Music is supposed to be fun and moving, right? Luckily MooTools and jQuery allow us to communicate that creativity on the web.
The XHTML
A few structure DIVs and the album information.
The CSS
The CSS...

Yes that’s for jQuery, but you can do the same easily with vanilla JS too.

m_gol

If you don’t support IE8, there are not a lot of reasons to care about IE9 that is so less used. And if youdrop IE9, you have Flexbox which solves this all without any hacks.

Troy

Correct me if I’m wrong (I know someone will), but it makes sense that IE9 has less use than IE8 because if you are still running XP(32), you cannot upgrade to IE9 or higher, but if you are running Vista, Win7, etc, you have more than likely updated IE along the way. Just an observation. But your point is still valid, but I’ll say that our shop only supports IE9 and above, unless we have a specific request from the client to support it, and we charge accordingly… I think.

Sorry, that was a bit off topic…

On topic now: I like this approach. I’ve used the 50/50 approach many times and works fine, but I’m in on a pure CSS approach. Codemaster D-dub on it as always.

Krzysztof

What about centering via positioning absolute with top, bottom set to zero and margin to auto in relative positioning container…

Brian

This is a great solution! And I personally have used it before, but sometimes you need more flexibility on your elements, like centering numerous elements in a row, so absolute positioning would turn it trickier. The good thing is that there are *many* ways to work around centering with CSS, so this is just one of ’em.

Nice detailed article about this technique. I’ve made an article earlier about alignment in CSS but doing the exact opposite: http://timseverien.nl/2013/10/css-alignment-and-sizing/
Instead of explaining it in detail, I just smacked several techniques and browser support in a post… hehe. I might add a link to this item if any of my users wishes to read more about this technique :)

I faced a similar issue at work yesterday: I had to vertically center images in squares, sized according to the viewport’s width for a thumbnails gallery. Of course I didn’t want to use any JavaScript, and it had to work back to IE 8.

Padding is based according the viewport width (don’t ask why), so using a vertical padding and width, you can create a fluid element that keeps it ratio at all times.

I guess the preferred method depends on the situation. In case of a gallery, I prefer your method when dealing with a gallery because you’re using img tags. This method however is nice for giant hero images and such.

Ava Sumter

The code in the article didn’t work but this did! Thanks Hugo

Nate Godfrey

First of all, a huge thanks to all contributors! That being said, Hugo’s solution takes the gold.

The problem with this technique is if your children has an odd height value.
Let’s say it’s 99px height and when you move -50%, the children will be positioned on a broken number (49.5px).
It does not affect images or text, but any other elements inside that contains a background color, border or anything like this will look blurred – SVGs are also included on the “blurred” list.
You can check a simple example here:http://codepen.io/lucasmotta/pen/hBcEw (notice on the second item, where the top border is blurred).

It’s a really simple and good technique, but you got be careful with what do you have inside your children.

Great solution but gotta be careful with hogging up the vram. Since CSS transform promotes a render layer to a GPU accelerated composite layer, if there are many elements vertically centered in this manner in the DOM, it may be taxing the vram a bit too much.

Thanks, this is exactly what I was looking for. I know that lots of people have their own little shortcuts on how to do things like this, but I was looking for an easy to understand and use technique that my team could use (for consistency and the like, you know?). Haven’t tried it any IE versions as of yet, so will keep my eye out for problems.

It isn’t here, and its styles aren’t important — just the children styles are.

Guest

I dont know why but it does not work for me.

I have a div that I want to center, I have put div inside another one (parent) and also I tried with only one div inside body. It only moves div 50% down. Seems transform: translateY(-50% does not work.
I tried Chrome and Firefox.

Hey, I’m the guest author of this post. Sorry, but I never implied I invented the method, as a matter of fact, I was trying to find the original article from where I learned this so I could link to it, but I failed to find it again as so much time had passed after reading it.

Somebody probably said it before, but here’s a BIG FAT warning about the “transform” approach: As this will essentially convert your element into a bitmap, which is then converted into a texture and moved to sub-pixel positions, it will almost certainly get your fonts blurred, which most of my customers (and sometimes, even I myself) find unacceptable…

Continue this conversation via emailGet only replies to your comment, the best of the rest, as well as a daily recap of all comments on this post. No more than a few emails daily, which you can reply to/unsubscribe from directly from your inbox.