The Wayback Machine - https://web.archive.org/web/20151209072141/http://staff.washington.edu/fmf/2010/03/25/centering-with-css/
  • CSS 25.03.2010

    Many designs call for centering content, either vertically or horizontally. It’s pretty straightforward to center horizontally, but if you wish to support Internet Explorer 7 and earlier, it takes a bit more work to center vertically.

    Other than older versions of IE, this page only targets the recent versions of Safari (4.0), Firefox (3.6), and Opera (10). Browsers which use the same engines as these (e.g. Chrome uses Safari’s Webkit) should behave similarly.

    Centering text

    Centering text in a container (such as a paragraph) is very straightforward.

    Centering text
    This text is centered.


    The HTML for this block is:

    <div>This text is centered.</div>

    and the necessary CSS is:

    div {
        text-align: center;
    }

    Note the actual CSS on this page includes a more complicated selector to target only this one <div>.

    The text-align property applies to a block element and centers all of the content in that block. If you show the background by enabling the checkbox, you’ll see that the block spans the width of its container, and centering the text within the block also centers the text within the outer container.

    Centering a block

    The previous example shows how to center text. Since text is an inline element, then its position is affected by the setting of text-align on the containing block. However, that attribute doesn’t apply to block elements.

    Centering a block
    Text in a <div> with width set to 50%, left and right margins set to auto.


    If you wish to center a block in another block, you can set the left and right margins to auto. The HTML for this example is the same as the previous one except for the actual text. The CSS is:

    div {
        width: 50%;
        margin-left: auto;
        margin-right: auto;
    }

    Enabling the background shows that the block is indeed centered within the container. The text itself, however, seems to be skewed slightly to the left, because it does not completely fill the width of the div.

    Floated blocks

    You cannot set margins to auto to center a floated block, as seen here.

    Centering a floated block
    This block is floated to the left.


    The only change to the CSS is to make the block float instead of setting the width:

    div {
        float: left;
        margin-left: auto;
        margin-right: auto;
    }

    This behavior follows the definition:

    If ‘margin-left’, or ‘margin-right’ are computed as ‘auto’, their used value is ‘0’.

    If you show the background, you’ll see that the block did indeed collapse in width, so while it ends up not being the full width of the container, the auto for the margins is interpreted as 0.

    Inline blocks

    Even though they are blocks, objects set to display as inline-block (such as images) are treated as inline objects when computing the margins.

    Centering an inline block

    This is set to inline-block.

    The block used in this example is a <span>, since older versions of IE can only set inline-block on objects which are normally inline. Again, the CSS is similar to the above examples:

    span {
        display: inline-block;
        margin-left: auto;
        margin-right: auto;
    }

    As with floats, the definition says:

    A computed value of ‘auto’ for ‘margin-left’ or ‘margin-right’ becomes a used value of ‘0’.

    Why isn’t my block centered?

    If you’re having problems centering a block by setting the margins, make sure the block isn’t spanning the full width of its container (which is the default).

    As shown above, floated blocks cannot use auto for the margins.

    Another thing to check is that you’re trying to set the margins on a block element, not an inline element (such as images or other objects explicitly set to inline-block).

    Vertical centering

    The easiest way to center objects vertically is to do it in a table cell. In fact, the CSS definition says vertical-align

    Applies to: inline-level and ‘table-cell’ elements

    However, there are many times when other tags make more sense semantically. One way around that is to use a <div> or other block elements and set it to display as table-cell. In order for that to work, you need to have it embedded in a block which has its display set to table.

    Vertical centering, table display
    This text should be centered vertically for recent browsers.


    The table block has a yellow background and the tcell block has a cyan background. Since there is no padding on the table block, none of the yellow background shows.

    The HTML for this code is:

    <div class="table">
        <div class="tcell">
            This text should be centered vertically for recent browsers.
        </div>
    </div>

    The CSS is:

    .table {
        display: table;
        height: 5em;
    }
    .tcell {
        display: table-cell;
        vertical-align: middle;
    }

    While it may be strange to put a table cell directly into a table without a table row, CSS allows for the automatic insertion of anonymous table objects:

    If the parent P of a ‘table-cell’ box T is not a ‘table-row’, a box corresponding to a ‘table-row’ will be generated between P and T. This box will span all consecutive ‘table-cell’ sibling boxes of T.

    IE 7 and earlier

    The markup and CSS for vertical centering are very straightforward, but since IE 7 and earlier don’t support these display types, another method needs to be used:

    Vertical centering, position
    This text should be centered vertically for IE 7 and earlier.


    The HTML requires one more wrapper block than the previous example:

    <div class="outer">
        <div class="middle">
            <div class="inner">
                This text should be centered vertically
                for IE 7 and earlier.
            </div>
        </div>
    </div>

    and the CSS:

    .outer {
        position: relative;
        height: 5em;
    }
    .middle {
        position: absolute;
        top: 50%;
    }
    .inner {
        position: relative;
        top: -50%;
    }

    IE 7 with colored backgroundsIf you’re on a browser other than IE 7 or earlier, the image at the right shows a piece of the example with the background enabled, and it shows how positioning is used. The yellow represents outer, the cyan middle, and the magenta inner.

    The outer box has a set height, and has position: relative because we want to position the middle box relative to it.

    The middle box is partially obscured, but it’s actually the same height as the magenta box. As you can see, the top of the cyan box would be half way down the yellow box.

    The top of the inner box is then moved up 50% the height of the cyan box, which then centers the content around the top of the cyan box, and thus centers the content in the yellow box. The reason inner is not set to position: absolute is that would cause middle to have no content (since inner would be removed from the content flow) and inner would be moved up 50% of 0, meaning not at all.

    IE 7 example on current browsers

    If you’re looking at this example in IE 8, Firefox, or Opera, you won’t see the cyan box, because inner does not get moved. In Safari, the top of the cyan box is in the vertical center of the yellow box and the magenta box is at the top.

    At first blush, it’s not clear why this method doesn’t work for all browsers. Since the position of the magenta box depends on the height of the cyan box, but the height of the cyan box depends on the height of the magenta box, it would seem logical that the magenta box layout should be done first, then the cyan box, then the magenta box repositioned. However, when computing the width of the cyan box, CSS3 says that using a percentage for the width of a box:

    Specifies a percentage width. The percentage is calculated with respect to the width of the generated box’s containing block. If the containing block’s width depends on this element’s width, then the resulting layout is undefined in CSS3.

    Since this statement is part of the definition of both width and height, presumably it also applies to height. It seems the other browsers are assuming that undefined means 0 and the top is moved up half of that, which is why it stays in place. Or, it could be that 50% of an undefined value is undefined, so the box doesn’t move. Either way, the result is the same.

    As for Safari, it seems if the height of the containing box is undefined, it uses the height of the next container which has a defined height, namely outer which has a height of 5em. Technically this doesn’t seem incorrect, but it’s not the expected behavior.

    Looking at the CSS2.1 spec, specifying a percentage for height says that it:

    Specifies a percentage height. The percentage is calculated with respect to the height of the generated box’s containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to ‘auto’.

    The difference from CSS3 is the height is auto rather than undefined. Again, it seems up to interpretation what the actual value should be.

    Note that setting an explicit height on middle would cause the magenta box to be positioned appropriately (since it would be clear that 50% of 5em is 2.5em), as would setting an explicit position for the top of the magenta box (since it wouldn’t depend on the height of the container). However, we wouldn’t want to do either, since we don’t know how tall the content would be for the magenta box (and therefore the cyan box).

    Vertical centering for both older and current browsers

    We can combine the two techniques to vertically center an object both IE 7 (and earlier) and the other current browsers.

    Vertical centering, mixed
    This text should be centered vertically for IE 7 and earlier, as well as recent browsers.


    The HTML is:

    <div class="table">
        <div class="tcell">
            <div class="inner">
                This text should be centered vertically
                for IE 7 and earlier, as well as
                current browsers.
            </div>
        </div>
    </div>

    The CSS is:

    .table {
        display: table;
        position: relative;
        height: 5em;
    }
    .tcell {
        display: table-cell;
        position: absolute;
        top: 50%;
        vertical-align: middle;
    }
    .inner {
        position: relative;
        top: -50%;
    }
    .table div {
        position: inherit;
        top: inherit;
    }

    If you show the backgrounds, table is yellow, tcell is cyan, and inner is magenta.

    At first glance this seems to be an unceremonious mash-up, and in a way it is. We know that IE 7 and earlier don’t understand display: table-cell, and it doesn’t matter if table has display: table for those browsers. Since vertical-align doesn’t apply to a plain <div>, IE 7 will ignore that, too.

    However, IE 7 also doesn’t understand using display: inherit, so it ignores that particular value for the tcell and inner blocks. With that, IE 7 shows the magenta block in the vertical center of the yellow box.

    With just the inherited position, Safari, Firefox, and Opera all show the magenta cell in the vertical center of the yellow box, but IE 8 does not. In fact, with only that override IE 8 would position the cyan cell half way down the yellow box, and the position the magenta box in the middle of the cyan box (presumably because the vertical-align takes precedence over the positioning).

    While IE 8’s behavior seems to make sense, the other browsers actually have it right. The CSS definition says of position: relative:

    The effect of ‘position:relative’ on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

    That means that tcell should not be pushed down. However, inner is just a normal block, so it seems that it should be moved up because of top: -50%. Even though it and tcell inherit position: relative, Safari uses the value of position: static for inner. It probably does that since tcell actually has an undefined value for position.

    Firefox and Opera both claim to use position: relative for inner and even have a negative value for top, but they also show the magenta box in the middle. It could be that, like IE 8, vertical-position takes precedence.

    To fix IE 8, we also add top: inherit so both tcell and inner inherit the top position of table (which defaults to 0). This also makes the positioning intent more explicit for Firefox and Opera (Safari will ignore it since it’s using static positioning). Just as with position, IE 7 and earlier do not know how to inherit top, so the end result is the magenta box is centered for all the targeted browsers.

    Posted by fmf @ 4:41pm

  • 2 Responses

    • Hey there, I think your site might be having browser compatibility issues.
      When I look at your blog in Firefox, it looks fine but when opening
      in Internet Explorer, it has some overlapping.

      I just wanted to give you a quick heads up!
      Other then that, excellent blog!

      • Thanks for the note. I haven’t tested against IE for a while. I’m using a pretty old template, so I suppose I’ll end up using a newer one which should fix the problem.

    Leave a Reply