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.
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.
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;
/* May want to do this if there is risk the container may be narrower than the element inside */
white-space: nowrap;
}
/* 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.
The example link is broken. Nice technique! Thanks! =)
Looks like JSfiddle is down. Hopefully it will be back up soon.
I have been looking for something like this. Can’t wait to see the demo :)
I think it is a real good example! I am also waiting for the demo…
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
Why would you want to add superfluous markup for something that can be done with a simple text-align:center in the style sheet?
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.
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: <a href=”http://jsfiddle.net/vTQBs/”>http://jsfiddle.net/vTQBs/</a>
Sorry, the updated test: http://jsfiddle.net/wFPhW/
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.
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.
In all seriousness, having a .centered class isn’t semantic either. It introduces design specifications into your html.
Should the declaration
vertical-align: middle
is placed on the selectors that containdisplay: table-cell
? One day I ever sawvertical-align: middle
is placed on the selectors that contain the declaration ofdisplay: table
(the parent element)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 ? ;)
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.
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?
of course – doesn’t vertically centre. apologies…
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.
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)
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.
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:
Stu Nicholls did a similar demo back in 2006 which might prove useful. He wrote about his solution:
Here’s the link to his demo:
Centering an image of unknown size in an outer container of known size
Does inline-block’s gap always has 0.25 em?
http://www.lifeathighroad.com/web-development/css-web-development/inline-block-whitespace-workaround/
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! :)
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='https://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!
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?
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
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 toheight: 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/I miss the deeper explanation of the solution.
– What is happening exactly
– Why do you need them both “middle-d”?
Hey Chris,
for me it’s the same as for Mark. When I set
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.
Yes, I miss!
All objects before have to be at height: 100% too.
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; }
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 :(
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.
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 :)
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>
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!
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.
Thanks for sharing :)
Very useful!
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.
Damn, CSS is ugly. Take a look at AXR Project (http://axr.vg). This thing will take you 3 lines of code.
So why are you at CSS-Tricks…?
So why are you at CSS-Tricks…?
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?
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…
Can’t claim I created this solution, but thought I’d share it with people! :)
Cool
this will come in handy! but how does inline-block behave? I’ve used inline-table and inline before.
When centering the “table-cell” element, don’t forget to remove the float:right | left.
Otherwise the vertical alignment does not work.
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
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.
And if there are multiple lines?
cheers,
gary
Multiple lines are no problem. I’ve updated the demo so that you can see that the inline-block can have any desired height: http://codepen.io/edge0703/pen/iHJuA
And if the parent is, say, 250px height?
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!
@ Chris Coyier:
Thanks for the mention. I just noticed this site as a referer this month.
gary
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 :))
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;
}
Oh really? Congratulations that you found this method now after it made the rounds about one month ago.
Awesome your comment worked like charm :)
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.
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.
Djeez! OK, I just found out why. In this :
I used
width: 100%
instead of apx
value. Changing100%
to the actual880px
resolved the issue. Works in all 5 now. But it’s not what I want. Nopx
value. It’s for a responsive navbar.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.
Hi Chris,
This approach does not seem to work for me with images. Anything that i am missing here?
http://jsfiddle.net/TmHe5/1/
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. :-)
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.
Still waiting for full flexbox and grid support to avoid problems like these.
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 aposition:fixed
layer and browser width gets set smaller than your centered element, it breaks into nowhere. A mediaquery could help with that :)My problem can be solved with white-space:nowrap. :)
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.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 */
}
`
You just save me a lot of brainbashing. Thanks!
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
Really – doesn’t work on iOs devices. With fixes Waseem provided – it’s not overflowing after the container, but not centering also.
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.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?
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.
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!
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 :)