Centering All the Directions

by Kyle Simpson

Since the dawn of civilization, mankind has struggled and strived, against all odds, to achieve that next level of human evolution; to stake out our place on this great planet, and in the universe around us; to boldly go where… Oh, never mind the hyperbole.

I would like to say, “Raise your hand if you’ve ever struggled with centering content in CSS, especially vertically?” But it’d probably be quicker to say, “Raise your hand if you haven’t struggled with…” CSS is an amazingly powerful tool, but there are some things, like vertical centering, that remain “too hard”™ even to this day. I’m going to explore various ways we center things, but propose we still need something better.

<center>

First off, if you’re still using <center> tag to center things, 1999 called, and they want their website back. Seriously, hand in your “modern web developer” membership card. You’re welcome back here once you’ve rid your code of this beastly monstrosity.

text-align:center

When it comes to centering text, you really can’t beat text-align:center. It does exactly what’s advertised on the box. It horizontally centers inline text within a parent container.

Example:

<style> #ex1_container { text-align:center; width:200px; background-color:yellow; }
</style>

<div id="ex1_container">Hello World</div>

 

Well, that was easy. The technique here is to instruct a parent element that we want its content (text) to have a certain positioning. We don’t directly style the content in question, but its container.

Except, this method only works on inline elements (and probably should only be used on text, but it’s not strictly limited there). And it only works in the horizontal direction.

vertical-align:middle

“But, but…” you say. “But what about vertical-align:middle?” Yeah, sounds like our solution. Turns out, not so much.

Unlike text-align:center, which is set on a parent element to describe how to center its content horizontally, vertical-align:middle goes on the content element itself, and doesn’t describe its position in its parent, only its position with respect to other inline content around it.

Yeah, useful for making inline text and inline images work nicely side-by-side, but it’s not the mystical vertical centering we’d like.

Note: You can use this trick with display:table on the parent and display:table-cell on the content element. Downsides: It’s back to tables, and it has poor legacy IE suppport.

line-height

A useful trick for vertically centering inline text is to set the line-height property of its container to the desired height, and the text should (roughly) vertically center itself. This is a common trick. Sometimes there are side effects to your line-height setting, and it’s not quite perfect (because of font metrics variations, etc). But hey, when all you have is a match-stick, everything looks like a pile of wood to start a campfire, right?

So, what do we do for centering of a block-level element?

margin:auto

Well, technically, we’d probably use margin: .. autowhere “..” was our vertical margin (we’ll come back to vertical in just a moment).

How does it work (horizontally)? Example:

<style>
  #ex2_container { width:200px; background-color:yellow; }
  #ex2_content { margin:0px auto; background-color:gray; color:white; display:table; }
</style>
 
<div id="ex2_container"><div id="ex2_content">Hello World</div></div>


NOTE: Because in this example I’m not defining an exact width for the #ex2_content element (I only want it to be as big as the text needs), to make it shrink/collapse around the text but still be center-able, I use display:table. You might think display:inline-block would work, but it doesn’t. But if you manually set the width or even max-width on #ex2_content, you don’t need to set display:table at all.

Cool, huh? Here, we just tell the content directly that we want it to center itself within its parent, horizontally of course. This is a little less semantic than text-align:centerbecause you’re sort of describing the space around the content rather than controlling the content itself. But we’ll give CSS a pass on that one. It’s not too bad.

So, you say: “Surely, that must work vertically, too!?” No, how idiotic are you for hoping for such a symmetric and simple solution!? Seriously, in what bizarre world did you learn CSS!?

Unfortunately, for reasons beyond mortal understanding, this “trick” doesn’t work in the vertical direction.

hacks, hacks

There are lots of other hacks which involve exotic things like negative margins, phantom extra ::before elements, and other crap. Most of them are quite brittle if your content is not of fixed-size.

If nothing else, it’s proof that we are a creative species when pressed for survival — we find a way to make it.

translate(-50%,-50%)

Hats off to Chris Coyier at CSS-Tricks.com for a recent hat trick reveal: using position and translate.

If you set position:absoluteon some child element, then set left:50%; top:50%on that child, its top-left corner will be centered both horizontally and vertically. Duh, we probably all knew that. But that’s not helpful because our content is almost never just 1×1 pixels.

The trick then, is translate(-50%,-50%). Whereas most percentage calculations of this nature, like leftand top, are of the parent container’s metrics, the percentages in translate(X,Y)are of the element itself.

So, we position the top-left corner in the middle of our container, and then “shift” it back half its width and half its height, and boom, magically it’s centered in both directions!

Example:

 

<style>
#ex3_container { width:200px; height:200px; background-color:yellow; position:relative; }
#ex3_content { left:50%; top:50%; transform:translate(-50%,-50%); -webkit-transform:translate(-50%,-50%); background-color:gray; color:white; position:absolute; }
</style>

<div id="ex3_container"><div id="ex3_content">Hello World</div></div>

This trick is certainly much more robust than some of the other hacks, because it gracefully responds to all the various conditions, like non-fixed-size content, min-width, max-height, overflow:scroll, etc. It basically does exactly what you’d hope it would do. It shrinks or grows (unless you constrain it), but stays centered regardless. Nice!

Go play around with it and see what it can do.

But, let’s be honest: it’s quite less semantic, and a bit uglier syntax-wise (especially because of those pesky vendor prefixes). And it falls into that category of over-compensation.

It’s probably the best technique out there so far, all things considered. But it makes me sad that we still have to write articles like this, and trick CSS into doing what we want.

Is that the best we can do?

If all these “tricks” and “hacks” sound like “junk science” to you, you’re not alone. Why is this so darned difficult? Why do we have to use different techniques for different scenarios?

What about one content positioning rule “to rule them all”? Shouldn’t there just be a standardized “thing” added to CSS to handle all the cases, instead of the hackery we currently have?

(conspiracy theory: CSS standards folks need to continue to fuel the fire of bloggers, so they leave some things unsolved on purpose!)

Here’s a modest proposal I just came up with:

<style>

  #ex4_container { content-positioning:50% 50%; width:200px; height:200px; background-color:yellow; }

  #ex4_content { content-positioning-anchor:50% 50%; background-color:gray; color:white; }

</style>

I’m suggesting here a content-positioning property on the parent element which controls the positioning of its child element(s). And content-positioning-anchor controls where the registration point is on the child element(s). It would, of course, default to 0px 0px, but if you set it to 50% 50%, you’d be saying, essentially, “put the middle of my content in the middle of my container.”

Bam! I just solved all the world’s problems. Well, not really. This hyperbole thing is addictive.

What do YOU think?

Let’s discuss what a single-unified-solution would have to look like. Or maybe there’s already super-secret CSS standards proposals for this that I’m not aware of. In any case, let’s dispense with the hackery and move towards standardization of this all-too-common use-case.

What do you think? Tell us!

Using this translation widget will provide you with a machine translation of the original content. The machine translation is provided for informational purposes only; it should not be relied upon as complete or accurate.