Vertically align div (no tables)

Viewed 21216

I can horizontally align a div and all the content looks nice. Looking to vertical align a div that does not contain any tables. I tried setting margin positions to some negative values inside of the #container but that sort of worked. I know CSS isn't supporting this yet?

Here is my markup:

body
{
    background: #777; /* gray */
    text-align: center;
}

#container 
{ 
    margin: 0 auto;
    width: 968px;
    text-align: left;
}

#toptab
{
    background: #f77; /* red */
    height: 14px;
    width: 968px;
}

#middletab
{
    background: #7f7; /* green */
    width: 968px;
}

#data
{
    width: 948px; /* 948 for the box plus we need 20 more px to handle the padding */
    padding-left: 10px; 
    padding-right 10px;
}

#bottomtab
{
    background: #77f; /* blue */
    height: 14px;
    width: 968px;
}
<div id="container">
    <div id="toptab"></div>
    <div id="middletab">
        <div id="data">
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
            The quick brown fox jumped over the big red bear.
        </div>
    </div>
    <div id="bottomtab"></div>
</div>

Run the snippet above and click "full page" to see how it currently looks. Basically, it looks great horizontally, but now I need it to also center vertically in the page.

The element that I want to align vertically is the #container div. The effect would force the entire div and all sub divs to not only be horizontally aligned but also vertically. I know this is possible and I know Andy Budd posted such a solution but it doesn't seem to work for me.

8 Answers

Unless you have the ability to explicitly set the height of your container (which doesnt look like that's the case), there is no cross browser solution for vertically centering your DIV container.

Using a table is completely viable, but you have noted that this cannot be used.

If javascript is an option, we could easily remedy this for you. A jQuery plugin already exists for vertically aligning a container.

(function ($) {
    // VERTICALLY ALIGN FUNCTION
    $.fn.vAlign = function() {
        return this.each(function(i){
            var ah = $(this).height();
            var ph = $(this).parent().height();
            var mh = (ph - ah) / 2;
            $(this).css('margin-top', mh);
        });
    };
})(jQuery);

And you would vertically align a DIV block like so:

$('#example').vAlign();

Taken from Simple Vertical Align Plugin.

Have a look at Vertical Centering With CSS or Vertically center content with CSS or CSS Vertical Centering. Method 3 of first reference is the same as CSS vertical center using float and clear.

And it's surely a good idea to test the result with a service like browsershots.org


EDIT: I modified your CSS and markup to implement Method 3:

css:

* {
  margin:0;
  padding:0;
}

html,
body {
  height: 100%;
}

body {
  text-align:center;
}

#floater {
  float: left;
  height:50%;
  margin-bottom: -100px;
}

#container
{
  clear:both;
  position: relative;
  margin: 0 auto;
  width:968px;
  text-align: left;
  height: 200px;
}

...

markup:

<body>
<div id="floater"></div>
<div id="container">

...

The drawback I see in this method is that with CSS you have to know in advance the height of your content, so that you can apply a negative margin of half this height to the floater. In the example I chose 200px.

See it in action.

There are a few ways to do this, all with compromises.

  • Use position:absolute, a fixed height, and overflow:auto.
  • Use display:table, display:table-cell, and vertical-align:middle
  • Use javascript

I think option #2 is pretty good.

edit: I don't think option 2 will work in IE. You may be stuck with javascript if you want to keep the height dynamic.

With pure CSS, this is only possible if the div has a fixed height. You can then position it absolute and set its top and left to 50% and the margin-top and margin-left to the negative half of its width and height respectively.

Here's an SSCCE, just copy'n'paste'n'run. The border is purely presentational, the remaining styles are required.

<!doctype html>
<html lang="en">
    <head>
        <title>SO question 1909753</title>
    </head>
    <style>
        #content {
            position: absolute;
            width: 300px;
            height: 200px;
            top: 50%;
            left: 50%;
            margin-left: -150px; /* Negative half of width. */
            margin-top: -100px; /* Negative half of height. */
            border: 1px solid #000;
        }
    </style>
    <body>
        <div id="content">
            content
        </div>
    </body>
</html>

If there is no means of a fixed height, then you'll need to grasp Javascript and live with the fact that client will see the div quickly being shifted to middle during page load, which might cause a "wtf?" experience.

If your main container's height is fluid, your only reliable choice is to use JavaScript ("reliable" is debatable here, of course). In JavaScript, you must first find the height of the container, then the window height and adjust the top offset accordingly. Here's how you'd do it in jQuery:

$(function() {
    $(window).resize(function() {
        var top = $(window).height() / 2 - $('#content').height() / 2;
        top = top < 0 ? 0 : top;
        $('#content').css('top', top);
    });
    $(window).resize();
});

And the CSS to make it work:

#content {
    position: absolute;
    /* Everything else is optional: */
    width: 960px;
    margin: 0 auto;
}

And the HTML:

...
<body>
    <div id="#content">Content here</div>
</body>
</html>

That's still quite simple, and will work if the user has JavaScript enabled.

Related