Grow your CSS skills. Land your dream job.

Centering in the Unknown

Published by Chris Coyier

When it comes to centering things in web design, the more information you have about the element being centered and its parent element, the easier it is. So what if you don't know anything? It's still kinda doable.

Not too hard: Known Child

If you know the height and width of both the element to be centered and its parent element (and those measurements won't change, i.e. not fluid width environment) one foolproof way to center the element is just to absolute position it with pixel values so it looks perfectly centered.

Let's say you know the exact width and height of the element you are centering, but the parent element can change in height and width.

You absolutely position the element to be centered and set the top and left values to 50% and the margin top and left values to negative half of the elements height and width. That was a tounge twister, so check this out.

Harder: Unknown Child

The hard comes in when you don't know the dimensions of the element to be centered.


What do we know? Nothing! When do we know it? Now!

The grossest way to handle it is literally tables:

<table style="width: 100%;">
  <tr>
     <td style="text-align: center; vertical-align: middle;">
          Unknown stuff to be centered.
     </td>
  </tr>
</table>

If you are worried about the semantics of that, you could attempt to match it to your content.

<div class="something-semantic">
   <div class="something-else-semantic">
       Unknown stuff to be centered.
   </div>
</div>

And get the same result as the tables like:

.something-semantic {
   display: table;
   width: 100%;
}
.something-else-semantic {
   display: table-cell;
   text-align: center;
   vertical-align: middle;
}

CSS tables might be fine for you. Or it might not. Tables do render a bit differently than just a regular block-level div does. For instance the 100% width thing. A table will only stretch to be as wide as it needs to for the content inside it whereas by default a block level element will expand to the width of its parent automatically. Also, god help you if you need other content inside that div that you want to position or otherwise not act as a table-cell.

Michał Czernow wrote in to me with an alternate technique that is extremely clever and accomplishes the same thing. If we set up a "ghost" element inside the parent that is 100% height, then we vertical-align: middle both that and the element to be centered, we get the same effect.


See what we did there?

So does that ghost element need to be an un-semantic element? Nope, it can be a pseudo element.

/* This parent can be any width and height */
.block {
  text-align: center;
}
 
/* The ghost, nudged to maintain perfect centering */
.block:before {
  content: '';
  display: inline-block;
  height: 100%;
  vertical-align: middle;
  margin-right: -0.25em; /* Adjusts for spacing */
}

/* The element to be centered, can
   also be of any width and height */ 
.centered {
  display: inline-block;
  vertical-align: middle;
  width: 300px;
}
View Demo

I'd like to tell you the ghost element technique is way better and should be the go-to centering technique for the ages. But in reality, it's just about the same as the table trick. The browser support for this is essentially everything and IE 8+. IE 7 doesn't support pseudo elements. But it doesn't support CSS tables either, so it's a horse apiece. If IE <= 7 support is needed, it's <table> time (or use an equally un-semantic <span> or something for the ghost element).

This stuff isn't brand new territory. Gary Turner wrote about it like 5 years ago. But I credit Michał for doing it with a pseudo element and making it the most semantic approach yet.

Note: The 0.25em nudge-back is a little janky. To do it perfectly, you could set font-size: 0; on the parent and then notch the font size back up inside the content container.

Comments

  1. The example link is broken. Nice technique! Thanks! =)

  2. I have been looking for something like this. Can’t wait to see the demo :)

  3. Permalink to comment#

    Very cool, I’m going to start using this! What’s really funny is that I miss using the old <center> tag because it would automatically horizontally center everything for you. Oh well :P

    • Permalink to comment#

      Why would you want to add superfluous markup for something that can be done with a simple text-align:center in the style sheet?

  4. Charlie
    Permalink to comment#

    I don’t see the advantage to adding the “ghost element.” Can you elaborate?

    CM

    • The ghost element is 100% height of the parent, so anything vertically-aligned with it will be centered with it. It’s what makes the whole thing work.

  5. I tried in your demo add a span within an html conditional comment for ie7-, defining the same properties (except by content), but that doesn’t work. So I changed the div’s by other span’s (due to the ie7- bug for assign inline-block to an natural block element), and worked!
    That’s a shame for semantic and code validation, but is better than use tables, is not it?
    The example: &lta href=”http://jsfiddle.net/vTQBs/”&gthttp://jsfiddle.net/vTQBs/&lt/a&gt

  6. Vendredi
    Permalink to comment#

    This generates so much code in CSS to avoid a simple 4 lines.

    Please tell me how a <table> is not semantic enough for this application ?

    • A table is an element to represent data, any other usage of it will not be semantic.

    • Pablo Botta
      Permalink to comment#

      Also you can make this CSS code reusable and then you can use it everywhere in your site like the “clean clearfix”. You gain in semantic and mantainability.

      I think is a great snippet.

      Thank you Chris

    • Seriously, are we still having this discussion? It’s 2011.

    • Hutch
      Permalink to comment#

      In all seriousness, having a .centered class isn’t semantic either. It introduces design specifications into your html.

  7. Permalink to comment#

    Should the declaration vertical-align: middle is placed on the selectors that contain display: table-cell? One day I ever saw vertical-align: middle is placed on the selectors that contain the declaration of display: table (the parent element)

  8. Then there’s (hopefully) the flexbox:

    box-orient: vertical;
    box-pack | box-align: center;

    And no word on how centering vertically is a progressive enhancement with jQuery being the master manipulator ? ;)

  9. Permalink to comment#

    Bravo! I was actually going to have a sit down and see if I could come up with something like this but this is way cleaner.

  10. John Holt Ripley
    Permalink to comment#

    Wouldn’t
    <div class="wrapper"><div class="inner">content</div></div>

    with
    .wrapper { float: left; position: relative; left: 50%; }
    .inner { float: left; position: relative; left: -50%; }

    work in this situation and be more elegant?

    • John Holt Ripley
      Permalink to comment#

      of course – doesn’t vertically centre. apologies…

  11. Awesome little technique! It makes me wonder how much untapped potential the :before and :after pseudo-elements still have.

    The more people realise how useful they are, the cleaner, I believe, everyone’s code can become.

  12. Permalink to comment#
    
    .inner {
        position: absolute;
        top: 50%;
        left: 50%;
        -webkit-transition: translateX(-50%) translateY(-50%);
    }
    

    Not crossbrowser of course, but anyway.

    • Did you mean transform? And it’s cross-browser solution for the latest final versions of all major browsers (except IE10)

      -webkit-transform: translateX(-50%) translateY(-50%);
      -moz-transform: translateX(-50%) translateY(-50%);
      -ms-transform: translateX(-50%) translateY(-50%);
      -o-transform: translateX(-50%) translateY(-50%);
      transform: translateX(-50%) translateY(-50%);
  13. sage
    Permalink to comment#

    It’s a very clever way to do that I didn’t know. Thanks !

    But that’s a shame there is no straight way to do something THAT SIMPLE. I really think css should be rethink from the start.

  14. Chris, when you don’t know the size of parent, but the size of the child is known, then there is another method of centering via pure CSS:

    
    #parent-element
    {
            position: relative;
    }
    
    #child-element
    {
           position: absolute;
    height: Xpx;
    width: Ypx;
           top: 0;
           right: 0;
           bottom: 0;
    left: 0;
    margin: auto;
    }
    
  15. Stu Nicholls did a similar demo back in 2006 which might prove useful. He wrote about his solution:

    IE 5, 6 and 7 uses inline-blocks and non-IE browsers use table-cell and vertical-align to emulate the table method.

    Here’s the link to his demo:

    Centering an image of unknown size in an outer container of known size

  16. Tobyyun
    Permalink to comment#

    Does inline-block’s gap always has 0.25 em?

  17. DRoss
    Permalink to comment#

    What I haven’t been able to figure out yet is if I have an anchor wrapping around a div, let’s say 200px x 200px.

    I want the entire div to be one big link, not just the text inside. Sometimes the text will wrap to two or more lines. I want the text centered vertically inside the entire block level anchor.

    Not worried about ie6 support but if anyone can do this and show an example I will send you $10! :)

  18. DRoss
    Permalink to comment#

    Might help with a little illustration if I’m not clear:

    ———————————————
    |
    | This text and entire
    | surrounding should
    | be centered and clickable
    |
    |
    ———————————————

    • To make an entire div a link, you can use “onclick” like this:
      onclick="location.href='http://css-tricks.com'"

      To make it appear as a link, you’ll also need to change the cursor in the css.
      cursor:pointer;

      Made an example for you:

      http://jsfiddle.net/R2eDQ/

      Hope I could help!

  19. Great trick, but the title ought to be “Centering -OF- the Unknown” :)

    The solution solves the problem of vertical centering when the height of the centered block (as opposed to its container) is unknown.

    It requires that the container have a known and fixed height.

    • No it doesn’t?

    • Christopher
      Permalink to comment#

      This also doesn’t work if the container element has a min-height — the pseudo-element immediately gets a height of zero. Edited Chris’s pen a bit:

      http://codepen.io/anon/pen/dFfmG

    • Permalink to comment#

      I had exactly the same issue as you Christopher: a container with a min-height set, but since child elements of parents with min-heights don’t adapt to height: 100%; as one might expect (as with the pseudo-element in this case), this was failing for me.

      What I did in the end was set the pseudo-element’s min-height to the same as the parent. This seems to work without issue, and doesn’t cause problems once the child element becomes taller than the parent. I’ve mocked up an example with comparisons and some visual indicators so you can see what’s going on: http://jsfiddle.net/XXQeB/

  20. Jason
    Permalink to comment#

    I miss the deeper explanation of the solution.
    - What is happening exactly
    - Why do you need them both “middle-d”?

  21. Permalink to comment#

    Hey Chris,

    for me it’s the same as for Mark. When I set

    .block {text-align: center; height: 100%;}

    because I don’t know the height of the browser window, all stuff inside went to the top. :( Did I miss something?

    Greetings from Berlin.

    • Permalink to comment#

      Yes, I miss!
      All objects before have to be at height: 100% too.

      html,body { height:100%; }
  22. KF
    Permalink to comment#

    Ferge,

    You’re right, vertical centering didn’t work for me either until I set html/body height to 100%.

    Chris,

    A curious thing happens when I minimize browser window to less than the specified content width — I get a vertical scroll bar, and content drops below the viewport. I fixed it by setting min-width of the body to match content width. Resulting CSS:

    html, body { height: 100%; margin: 0; }
    .wrap { width: 100%; height: 100%; text-align: center; }
    .wrap:before { content: “”; display: inline-block; height: 100%; vertical-align: middle; margin-right: -0.25em; }
    .centered { display: inline-block; vertical-align: middle; width: 960px; }
    body { min-width: 960px; }

  23. Graham B
    Permalink to comment#

    Also, god help you if you need other content inside that div that you want to position or otherwise not act as a table-cell

    I’ve been needing to do exactly this; a centered, variable-height image within a known parent, with a caption aligned underneath the image. I simply don’t think this is possible without JS :(

  24. Ingo Chao
    Permalink to comment#

    Every period has its own techniques. Several years ago, we did know about the limitations of the browsers, so pseudo-elements were not an option. Bruno Fassino tested the combination of display: table-cell for “modern” browsers, combined with display: inline-block hacks for IE. http://www.brunildo.org/test/vertmiddle.html and http://www.brunildo.org/test/img_center.html
    Gary Turner’s article describes the technique very well. And Chris Hester already noted that Stu had similar tests and solutions.
    Seen from today, it is short-sighted to point out these solutions as “un-semantic”. It was the best you could get at that time — you are standing on the shoulders of giants.

  25. Permalink to comment#

    Hey Chris, here centering a div on a page made easy :) working in any possible browser, or at least in all I tested.

    The whole article here: http://www.kensfi.com/how-to-align-center-a-div-with-no-width-declared/

    btw 2 lines of CSS and valid markup :)

  26. Permalink to comment#

    here again, sorry… just tired after the day.

    <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
    <html xmlns=”http://www.w3.org/1999/xhtml”>
    <head>
    <meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
    <title>Untitled Document</title>
    <style type=”text/css”>
    ul { text-align: center; }
    li { display:inline; padding:0 10px 0 0 }
    </style>
    </head>
    <body>
    <div>
    <center>
    <ul>
    <li><img src=”http://www.kensfi.com/images/pict.jpg” width=”200″ height=”166″ /> </li>
    </ul>
    </center>
    </div>
    </body>
    </html>

  27. Finally! I’ve tried so many techniques to center elements inside a wrapper and this is far best I’ve seen

    Congrats and thanks for sharing!

  28. Permalink to comment#

    Funnily enough I had this exact same problem yesterday and resorted to using a nasty old table. I do need support for IE7 so I guess will leave it as-is for now.

  29. Permalink to comment#

    Thanks for sharing :)
    Very useful!

  30. Permalink to comment#

    the real question is: why didnt w3c try to figure this one out since ages? may be becuase centering vertically is not a style related issue, or thats how w3c see it! to me, centering vertically to an unknown parent is very much a dynamic-visual effect, thus belongs to behavioral layer… javascript that is. e.g. lightboxes, u already need js to pop open the box, u might as well let js position it.

    visual effects proly assume knowledge of parent width.

  31. Permalink to comment#

    Damn, CSS is ugly. Take a look at AXR Project (http://axr.vg). This thing will take you 3 lines of code.

  32. Permalink to comment#

    Just to be clear, using unsemantic code purely for layout purposes is correct.

    We use divs to wrap our content because they have NO semantic meaning, not because they have the right semantic meaning. The same goes for spans.

    Using a table, in this case, is incorrect because tables have an inherent semantic meaning.

    By using spans and divs, we are not getting the semantics wrong; we’re just not being semantic at all. In this case, it is a good thing.

    Am I right, Chris?

  33. Permalink to comment#

    The solution I use is the same as Chris’s original solution but extended to be browser & version compatible…so, Chrome, Firefox, Opera & IE (6 through 10).

    You don’t need to know any height or width and works in every major browser + versions for the last 10 years.

    No JS, just CSS hacks…

    Demo:
    http://www.mattpass.com/lab/hCenterVCenter

    The CSS…

    .mainContainer {
    	position: absolute;
    	display: table;
    	width: 100%;
    	height: 100%;
    	top: 0px;
    	left: 0px;
    	text-align: center;
    }
    .mainContainer .vCenter {
    	#position: absolute;
    	display: table-cell;
    	#top: 50%;
    	vertical-align: middle;
    	text-align: center;
    }
    .vCenter .heyImCentered {
    	#position: relative;
    	#top: -50%;
    	text-align: center;
    	display: inline;
    	background-color: red;
    	color: white;
    }
    

    Can’t claim I created this solution, but thought I’d share it with people! :)

  34. Chris
    Permalink to comment#

    Cool

  35. Permalink to comment#

    this will come in handy! but how does inline-block behave? I’ve used inline-table and inline before.

  36. Permalink to comment#

    When centering the “table-cell” element, don’t forget to remove the float:right | left.
    Otherwise the vertical alignment does not work.

  37. Zámbó Gergő
    Permalink to comment#

    Heya, Thanks for sharing this!

    I wonder what would be that case when I need to vertically center something and the text must be aligned to the left side?

    I have a site with collected poems and I just can’t figure out a bullet-proof solution, because every poem has differing line widths.

    Plus it’s a typographic expectation that the title of each poem should be in the center of the avarage line width.

    Would be so happy if you could think about this for me.

    Cheers,

    Greg

    • Only a couple of years late, but the solution iss actually very simple:
      .verse pre {
      display: table;
      margin: 0 auto;
      }

      cheers,

      gary

  38. I found an even easier method which needs no pseudo-element: http://codepen.io/edge0703/pen/iHJuA

    Just set height and line-height to the same value for the container.

  39. Permalink to comment#

    The ghost element technique doesn’t work on an absolute positioned .block container, even if the height of this container is set. The css table way I don’t know yet, going to try it out now =) Thanks for the tips though!

  40. @ Chris Coyier:

    Thanks for the mention. I just noticed this site as a referer this month.

    gary

  41. Julius
    Permalink to comment#

    this seems to be not working an file.
    it horizontally centers, but the vertical align only works when there is no .

    any help would be greatly appreciated :))

  42. Permalink to comment#

    The easiest way, just define dimensions and live longer, the article is pointless.

    .Absolute-Center {
    margin: auto;
    position: absolute;
    top: 0; left: 0; bottom: 0; right: 0;
    width: 100px;
    height: 100px;
    }

  43. Kristi
    Permalink to comment#

    At mobile sizes, this ghost method seems to force the centered content outside of and below its parent whereas the display: table method rocks on.

  44. Robert
    Permalink to comment#

    On Win7, Michal’s method works perfectly in Chrome v31.0.1650.57 m, Opera v12.16, and Safari v5.1.7 (7534.57.2) (abandonware).
    It fails on Internet Explorer v9.0.8112.16421 Update v9.0.22, and Firefox v25.0. The element to be vertically centered is pushed down outside it’s container. Its top kissing the bottom. :)

    It’s a bloody disgrace that we still have to pull these tricks.
    2+ years after this article, 7+ years after Gary Turner’s article.

    Travel time to Mars is 250 – 300 days.
    Determined by the distance (it varies by millions of kilometers every 2 odd years), the size of the space craft, the travelling speed, the engine, and the amount of fuel which can be carried (less fuel = lower speed = slower travel time).

    Let’s assume the guys at NASA (or any other space agency) had a boozer. They drank some of the fuel. OK, so less fuel, and thus slower speed. Let’s say it takes the space craft 365 days to reach Mars. Since Gary Turner wrote his article, (7+ years ago in mid 2006) that would mean that at least 2 space craft reached Mars. Maybe even 3, depending on when the closest point between the 2 planets was reached.

    And these browser vendors can’t even give us a “vertical-center” property for this.

    The people at NASA (and other space agencies) must be laughing themselves silly : “It’s not exactly rocket science. ”

    P.S. We can’t be sure of anything though. Even if there would have been a W3C spec for a “vertical-center” property, our browser vendor friends (at, or not at the W3C) would probably all have their own interpretation and implementation of it.

  45. Robert
    Permalink to comment#

    Djeez! OK, I just found out why. In this :

    .centered {
      display: inline-block;
      vertical-align: middle;
      width: 300px;
    }
    

    I used width: 100% instead of a px value. Changing 100% to the actual 880px resolved the issue. Works in all 5 now. But it’s not what I want. No px value. It’s for a responsive navbar.

  46. You made a note saying the margin right is a bit janky, I thought that too, why not just utilize both pseudo elements: http://codepen.io/mikevoermans/pen/hvwfn

    This would keep them centered too.

  47. Anand
    Permalink to comment#

    Hi Chris,
    This approach does not seem to work for me with images. Anything that i am missing here?

    http://jsfiddle.net/TmHe5/1/

  48. Fabian
    Permalink to comment#

    Just found a little bug in Safari.

    If you want the centered element (centered) the same width as the parent element (block) and use a sans-serif fontface the positioning won’t work correct. In order to get it working you can use the “font-size: 0-method” as described at the end of the article.

    If there’s another better work around… tell me. :-)

  49. Permalink to comment#

    Thanks for these techniques. But after some experimenting, i realized that many of this solutions make some trouble, in different scenarios.
    Staying with the good old table centering, seems the fast and most solid for me.

    <div id="parent" style="display: table;">
       <div id="child" style="display: table-cell">
       </div>
    </div>
    

    Still waiting for full flexbox and grid support to avoid problems like these.

  50. I like the vertical-align:middle approach a lot. Unfortunately it has one downside. Although its no blocker: if you use this technique to show a position:fixed layer and browser width gets set smaller than your centered element, it breaks into nowhere. A mediaquery could help with that :)

  51. My problem can be solved with white-space:nowrap. :)

  52. seanjacob
    Permalink to comment#

    When setting the centered element to width:100% in FF [27.0.1] it gets pushed under :before, to prevent this I put the nudge back (margin-right:-0.3em;) on the centered element instead.

  53. Waseem
    Permalink to comment#

    Thanks for the share Chris … very elegant solution for when you need to layer a vertically centered div over an image on a responsive website :)

    I found it broke on smaller screens but with this simple wee edit all is well in vertical centering land :)

    `/* The ghost, nudged to maintain perfect centering /
    .block:before
    {
    content: ”;
    display: inline-block;
    height: 100%;
    width:1px; /
    set the width to 1% so the .block-item div doesn’t wrap onto the next line /
    vertical-align: middle;
    margin-right: -0.25em; /
    Adjusts for spacing */
    }

    /* The element to be centered, can
    also be of any width and height /
    .block-item
    {
    display: inline-block;
    vertical-align: middle;
    max-width:99%; /
    set this to 99% so it doesn’t wrap onto the next line */
    }
    `

  54. Marcel Bootsman
    Permalink to comment#

    You just save me a lot of brainbashing. Thanks!

  55. Thanks a lot for these!

    Unfortunately the pseudo-element solution does not seem to work on iOs (Chrome / Safari) when you don’t set a width on the .center and only use paddings. The top gets shoved down to the bottom of the parent element. I have no idea why

  56. Rootical V.

    Really – doesn’t work on iOs devices. With fixes Waseem provided – it’s not overflowing after the container, but not centering also.

  57. Tim Finley

    This still seems to require an explicit height to be set. True, that height can be variable, but here is an example that doesn’t work. In it the parent is a clearfix-ed container with no height set (and the height is determined by a float inside of it). In this case, the height: 100% set on the generated content seems to take no affect.

  58. Bob Bobson

    What about centering an element that has its overflow set to hidden. For example, if you want to have an element act as a view-port into a large image. How can the “window” be set to the center of the image?

  59. James Hinson

    Awesome info!! After some adjustments it fits my needs perfectly.

    Also to get the parent div height to work as a percentage, set it’s position to absolute.

  60. Daniel

    This is a beautiful solution! Thank you and Michał Czernow for sharing! Also, thanks for the great site! I’ve discovered it a few days ago and I’ve been coming here quite often!

  61. John

    Great trick !
    However, the ::before technique does not work when the parent element (“.block” in your example) has a height set with a percentage. The counter to that is to use a div instead of a pseudo-element :)
    Cheers :)

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".