24

how could i vertically center a <div> within a <div> ?

my code so far:

<div style="height:322px;overflow:auto;">
    <div style="border: Solid 1px #999999;padding:5px;">
    </div>
</div>

i have tried "top:50%;" and "vertical-align:middle;" without success

EDIT: okay so it's been discussed a lot. and i've maybe started another mini flame war. but for argument sake, how would i do it with a table then? i've used css for everything else so far so it's not like i'm not trying to employ "good practices".

EDIT: the inner div does not have a fixed height

cgp
  • 41,026
  • 12
  • 101
  • 131

10 Answers10

33

In short, you're stuffed. More on this in a recent question I asked Can you do this HTML layout without using tables? Basically the CSS fanatics need to get a grip and realize there's simply some things you can't do (or can't do well) without tables.

This anti-table hysteria is nothing short of ridiculous.

Table cells handle vertical centering really well and are backwards compatible as far as you could possibly care about. They also handle side-by-side content way better than floats, relative/absolute positioning or any of the other CSS type methods.

Joel coined (or at least popularized) the term "architect astronauts" in Don't Let Architecture Astronauts Scare You. Well, in that same vein I think the term "CSS Astronaut" (or "CSS Space Cadet") is equally appropriate.

CSS is an incredibly useful tool but it also has some pretty serious limitations. My favourite ishow numbered lists may only appear as "3." but not "3)" or "(3)" (at least prior to CSS3 generated content--or is it CSS2.1? Either way it's not widely supported). What an oversight.

But bigger than that is vertical centering and side-by-side layout. These two areas are still a huge problem for pure CSS. Another poster decided the relative positioning combined with negative margin heights was the way to go. How is that any better than:

<html>
<head>
  <title>Layout</title>
  <style type="text/css">
    #outer { height: 200px; border: 1px solid black; width: 600px; background-color: #DDD; }
    #inner { width: 150px;  border: 1px solid red; background: yellow; margin: auto; line-height: 100%;  }
  </style>
</head>
<body>
<table>
<tr>
<td id="outer">
  <div id="inner">Inner</div>
</td>
</tr>
</table>
</body>
</html>

which will work everywhere, everytime.

Here is an article on vertical centering in CSS. To achieve a similar thing they use three nested divs with relative+absolute+relative positioning just to get vertical centering. I'm sorry but whoever wrote that--and anyone who thinks that's a good diea--has simply lost the plot.

A counterargument is given in Tables vs CSS: CSS Trolls begone. The proof really is in the pudding. The vast majority of the top 20 (Alexa) sites still use tables for layout. With good reason.

So decide for yourself: do you want your site to work and spend less time getting it to work? Or do you want to be a CSS Astronaut?

Community
  • 1
  • 1
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 16
    Tables are also *completely* unacceptable for layout purposes where their content is not tabular. You table layout proponents need to realise that their are only appropriate to one problem and the cost of failing a desing is far less serious than failing semantics. – annakata Feb 09 '09 at 11:47
  • 5
    "failing a desing is far less serious than failing semantics" ...are you serious on that one? Business holders are OK with that? – Ionuț G. Stan Feb 09 '09 at 11:55
  • 10
    What if it takes a developer 5 hours just to get a UI semantically correct, that would take him about 10 min to solve using tables. What should that developer tell its boss or client? I had to get that right, so please pay me my $100 per hour, it's important?! – Sebastian Hoitz Feb 09 '09 at 12:03
  • 1
    @Ionut: absolutely, because a serious web shop doesn't output bad design to build to in the first place, and support will evolve but bad markup will remain. Further, good CSS guys know how to do this. – annakata Feb 09 '09 at 13:24
  • @Sebastian: no, then we gently (or not so) berate the dev for not asking one of the senior guys how to do this. – annakata Feb 09 '09 at 13:26
  • 3
    annakata, i'm sure you're correct, but i selected this answer because it's easy and works...for me. where i am there are no "senior guys", and if i were to try do things the "proper" way every time, i'd get nothing done. –  Feb 09 '09 at 13:29
  • @Jay: no worries, cletus argument is certainly not without pragmatic value (clearly it has some for you) – annakata Feb 09 '09 at 13:31
  • 2
    This actually a poor answer. The markup, as others have indicated, should be semantically correct and avoid tables except for tabular data. CSS provides all the workaround necessary, through the use of display:table, display:table-cell, etc., which can be applied to any html element. – Joshua Jul 10 '12 at 20:35
  • CSS is so inherently broken and badly designed it is impossible to say what is "proper". Like asking what is the proper way of using Yugo for space travel. http://en.wikipedia.org/wiki/Zastava_Koral – Ska Apr 03 '14 at 12:57
  • 1
    @cletus - can you make some significant changes to this answer? It is horrifically outdated and this is one of the top Google results for vertically centering. It isn't very good advice in 2014. Ideally it should be community wiki and edited with the best CSS techniques so we can send the many duplicates this way. – misterManSam Oct 28 '14 at 05:35
9

It's non-trivial, there can be caveats, and it's not something CSS handles well at this point.

It is however quite widely discussed and googleable. This is a good example.

Whatever you do, please don't fallback to tables.


Edit: this is ridiculous, the following works perfectly well in a strict doc without resorting to table markup:

<style type="text/css">
.outer {height: 322px; overflow: hidden; position: relative;}
*|html .outer {display: table; position: static;}

.middle {position: absolute; top: 50%;}
*|html .middle {display: table-cell; vertical-align: middle; position: static;}

.inner {position: relative; top: -50%; overflow: auto;}
*|html .inner {position: static; max-height: 322px;}
</style>
<!--[if IE]>
<style>
.inner {height: expression(Math.min(this.scrollHeight,322)+'px'); width: 100%;} /* for explorer only */
</style>
<![endif]-->

<div class="outer">
    <div class="middle">
        <div class="inner">
          Any text any height
        </div>
    </div>
</div>
annakata
  • 74,572
  • 17
  • 113
  • 180
  • 7
    Downvoted for anti-table fanaticism. You can't on the one hand say "It's non-trivial, there can be caveats, and it's not something CSS handles well at this point." and then on the other hand "oh, don't use the solution that is easily implemented and works everywhere". – 17 of 26 Feb 09 '09 at 13:16
  • 4
    Given that what I actually said was there are problems but *here* is how you do it, yes I can say it. I have never worked anywhere where semantics were less important than design, because design is easily tweaked and support will evolve over time, but broken markup will always be broken markup. – annakata Feb 09 '09 at 13:21
  • 1
    (but thank you for explaining your position, I genuinely appreciate that) – annakata Feb 09 '09 at 13:28
  • @17of26: Strictly speaking, the question was for a CSS solution, not an HTML solution. ;-) – T-Bull Jul 01 '13 at 17:25
7

I like this solution best. It is for IE8+, and is easy to understand.

<style>
/* Can be any width and height */
.block {
  height:500px;
  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 be any width or height */ 
.centered {
  display: inline-block;
  vertical-align: middle;
  width: 300px;
}
</style>

<div class="block"><div class="centered">Centered Content</div></div>
Justin
  • 26,443
  • 16
  • 111
  • 128
5

top: 50%; should work. you need to put margin-top to negative half of the height or it will start in the middle. Therefore, you need the height of the inner div. You also probably need position:relative;

Something like this for you inner div.

position:relative;
top: 50%;
height:80px;
margin-top: -40px; /*set to a negative number 1/2 of your height*/

Not very neat working with negative sizes (what does it even mean?) but maybe the easiest way.

Jens Jansson
  • 4,626
  • 4
  • 25
  • 29
  • "what does it even mean" hehe. yeah i get that feeling every time i do CSS. maybe it's just not my cuppa tea. –  Feb 09 '09 at 12:04
2
<div style="display: table; height: 400px; #position: relative; overflow: hidden;">
  <div style=" #position: absolute; #top: 50%;display: table-cell; vertical-align: middle;">
    <div style=" #position: relative; #top: -50%">
    vertically centered
    </div>
  </div>
</div>

more information

Stefan Ladwig
  • 569
  • 9
  • 19
1

Two techniques of many

Browser compatibility of the following has been tested in IE only. Modern browsers should handle these no problem.

#1 - Absolute and auto margin

Compatibility: IE 8 +

  • The combination of top, right, bottom, left and margin: auto centers the div vertically and horizontally.

  • The width and height are needed, but can be percentages

Can also be applied to an inner div with the parent set position: relative

Note: A max-width and max-height instead of a percentage height is possible IE 9 +. IE 8 requires a height.

html,
body {
  height: 100%;
}
.outer {
  background: #ff8f00;
  height: 50%;
  width: 50%;
  margin: auto;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
<div class="outer"></div>

#2 - Flexbox

Compatibility: IE 11. See here for other browser support.

Using Flexbox and flexible vw and vh lengths

body {
  margin: 0;
}

.outer {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.inner {
  width: 50vw;
  height: 50vh;
  background: #ff8f00;
}
<div class="outer">
  <div class="inner">

  </div>
</div>
misterManSam
  • 24,303
  • 11
  • 69
  • 89
0

A table isn't necessary if you're willing to use the flexbox display model.

E.g.

<div style="height: 322px; width: 200px; display: flex; background: gray;">
    <div style="border: Solid 1px #999999; padding:5px; margin: auto;">
      This text would be both vertically AND horizontally centered, if it's inner height and width were less than the parent's height and width.
    </div>
</div>

If you just want vertical centering use the rule "margin: auto 0;" in the child div.

p.s. You'll have to prefix your use of flexbox if you want cross-browser compatibility (e.g. "display: -webkit-flexbox;")

jonathan3692bf
  • 1,398
  • 1
  • 12
  • 14
0

The display: flex property works especially well for centering, both vertically and horizontally. For vertical centering, add the properties display: flex and justify-content: center to the container.

serebit
  • 400
  • 2
  • 13
0

Do you absolutely need to do this with css? The above link looks pretty good, but you could get a result using javasctipt/jquery - determine the height of the innter div and adjust the margin.padding accordingly. Something similar to: (jquery)

var gap = ( $('the-outer-div').height() - $('the-inner-div').height() ) /2;
$('the-inner-div').css( "margin-top" , gap );
Andrew
  • 1,251
  • 6
  • 17
-3

Try line-height

omoto
  • 1,212
  • 1
  • 17
  • 24