CSS: horizontal and vertical centering that really works (yes, really)

Ah the joys that arrived with CSS and the banishment of the good old CENTER tag which, well, centered things.

I provide here some minimal examples live that show you exactly how horizontal
and vertical centering in CSS really work (including some variations and options).

I also provide some links at the bottom here with lengthy discussions (and arguments) about everything to do with horizontal and vertical alignment. I highly recommend the following article, which does a great job of explaining the difference between "default" block level and "default" inline display mode elements, although there are some markup problems with the HTML code representation: Horizontal and Vertical Centering Using CSS: A Beginner’s Guide by Jarod Taylor:

'There comes a time in every web designer's life, when you're trying to center an HTML element and it's failing miserably. You're ready to pull the plug on CSS, revert back to tables, and use deprecated tags and attributes like: <center>, align, and valign.'

Horizontal centering with CSS, the (relatively) easy bit

The most important thing to understand is that the CSS 'text-align' property applies to the (typically inline) children of a container block element, not to the block element itself, and certainly not to an inline element itself. You therefore can't center an image using a lonely inline IMG tag like this:

.CENTER { text-align: center;}

<img class="CENTER" src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/>

The reason this fails (aligns left) is that the IMG is by default an inline element and has no children to align, the CENTER class here has nothing to apply to, it does not apply to itself (the IMG).

Instead, we try next to wrap it in a centering DIV block container element, and we also include a simple border so we can see the containing DIV:

   border: 1px solid silver;

<div class="CENTER BORDERED">
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/>

It works fine, because the containing DIV takes up 100% of the available content area width (unlike a TABLE element, which 'will only take up as much width as it needs, similar to an inline element'):

'When a block-level element doesn't have a width declared, its default value is auto. If a block element has the width value of auto, it will take up 100% of the width of its parent element.'

Centering a block level element

One can center any element that is by default - or forced to be - a block display mode element without consideration of its container using automatic margins on each side of the element:

    margin-left: auto;
    margin-right: auto;

We can force a SPAN to have block display and can then center it within the content area. (In the examples below, the DIVs are by default 'block' display mode anyway, but it doesn't hurt to have it in the CSS above.)

<span class="BLOCK-CENTERED BORDERED">SPAN forced block: Centered, but as wide as the content area anyway (but text left).</span>
<div class="BORDERED">DIV: Will inherit horizontal alignment from its parent container, and stays left (and text left).</div>
<div class="BLOCK-CENTERED BORDERED">DIV: Centered, but as wide as the content area anyway (but text left).</div>

But you won't see any difference for these SPANs or DIVs, because - being all block elements now - they are by default 100% wide anyway. Look at the borders !

SPAN forced block: Centered, but as wide as the content area anyway (but text left)

DIV: Will inherit horizontal alignment from its parent container, and stays left (and text left).
DIV: Centered, but as wide as the content area anyway (but text left).

The text within that SPAN and those DIVs is NOT centered, because it has inherited a left alignment; the block-forced SPAN and DIVs _are_ centered, but because they are 100% wide anyway it makes no difference.

To see a difference, we have to force them all to be less than 100% of the content area width:

.HALF-WIDTH { width:50%;}

<span class="BLOCK-CENTERED BORDERED HALF-WIDTH">SPAN: half width, and centered (but text left).</span>
<div class="BORDERED HALF-WIDTH">DIV: half width, and will inherit horizontal alignment from its parent and stays left (and text left).</div>
<div class="BLOCK-CENTERED BORDERED HALF-WIDTH">DIV: half width, and centered (but text left).</div>

SPAN: half width, and centered (but text left).

DIV: half width, and will inherit horizontal alignment from its parent and stays left (and text left).
DIV: half width, and centered (but text left).

Again, the text alignment within the block level elements is not of interest here, we are examining only the alignment of the block level outer elements shown by the borders ! We could easily align the text within them each by including the CENTER class from above, which will then apply to the contained text:

<span class="BLOCK-CENTERED BORDERED HALF-WIDTH CENTER">SPAN: half width, and centered (and text centered).</span>
<div class="BORDERED HALF-WIDTH  CENTER">DIV: half width, and will inherit horizontal alignment from its parent and stays left (but text centered).</div>
<div class="BLOCK-CENTERED BORDERED HALF-WIDTH  CENTER">DIV: half width, and centered (and text centered).</div>

SPAN: half width, and centered (and text centered).

DIV: half width, and will inherit horizontal alignment from its parent and stays left (but text centered).
DIV: half width, and centered (and text centered).

Centering an IMG without a DIV container by forcing it to be a centered block element

The same automatic margin trick can be applied to an IMG forced to be a block element, without even specifying a width for it:

<img class="BLOCK-CENTERED BORDERED" src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/>

The reason this works is that IMG has "intrinsic dimensions", it does not even need a width declaration, it will - unlike other block elements - not automatically expand to 100% of the width of its parent !

Vertical centering of multiple images

Fine, we can handle horizontal centering of text and images. Now what if we have 2 images of different heights and we have to consider vertical centering as well:

<div class="CENTER BORDERED">
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/><img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/>

Note also that because this is being done in Drupal™, I have taken special care to use no newline between the 2 <img> elements, because the Drupal line-break text filter will (if enabled) turn that line-break into a <BR/>, thus:

<div class="CENTER BORDERED">
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/>
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/>

Above, the Drupal line-break text filter (input filter) has inserted a <BR/> and separated the images so they are now on top of each other, instead of beside each other.

Ok, back to the side-by-side images. In order to align them vertically using DIVs, we might naively think we need to "make the container align them", just as we did with horizontal alignment of its child images, like this:

.MIDDLE {vertical-align: middle;}

<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/><img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/>

It fails ! So why if the container DIV works fine for horizontal centering does it fail here for vertical alignment of its child elements ?

As Jarod Taylor says:

'Unlike horizontal centering, vertical centering can be a nightmare. There [are] a few different methods of vertically centering content in HTML, but all methods have their pros, cons, and browser inconsistencies.'

The first thing to understand is that:

Outside a good-ol' TR tag within a TABLE, the 'vertical-align' does not align the child elements within a "container" element it is applied to, it aligns the element that it is applied to relative to the baseline of its parent !

Further, except for the special case of block elements with the special display type 'table-cell', it is really intended for use with inline elements, it instructs them how to "align themselves" vertically within their (usually block display type) parent. From Vertical Centering With CSS:

'Poor vertical align still gets a bad rap ...

I think this is because most coders would expect vertical-align to align an element vertically in its container. Instead it vertically aligns an element in relation to the line-height. '


'The basic usage is like this:

img {
   vertical-align: middle;

Notice in this usage case, it is being applied to the img element. Images are naturally inline elements, meaning they sit right inline with text if they are able to. But what does “sit inline” mean exactly? That is where vertical-align comes in.

The valid values are: baseline, sub, super, top, text-top, middle, bottom, text-bottom, length, or a value in percentage.

The confusion, in my opinion, sets in when people try to use vertical-align on block level elements and get no results. If you have a small div inside a larger div and want to vertically center the smaller one within, vertical-align will not help you. '

The CSS table/row/cell-like DIV vertical centering approach: flexible but complex

Let's look first at the approach you will probably see "recommended" most often, the table-like DIV strategy. CSS offers at least three table-like display modes: 'table', 'table-row', and 'table-cell', which we can encapsulate as CSS classes thus:

/* Special table forms, not supported by IE6, IE7 (but only tiny usage) */
    display: table;
.ROW {
    display: table-row;
    display: table-cell;
    padding: 5px;

The markup is quite like TABLE/TR/TD. The use of a 'display: table-row;' DIV here is optional, but the use of the outermost 'display: table;' DIV is NOT optional, otherwise the 'display; table-cell;' DIVs will have no vertical alignment reference (no sensible baseline):

<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/></div>
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/></div>

But there is still a problem, it is all left-aligned. That is because the outermost 'display: table;' DIV now acts like a TABLE and does not expand to take up 100% of the content area !

We might be tempted to simply add in a 100% width specifier for the container table DIV; after all, that seemed to work with horizontal centering of a single image above within a DIV, where the DIV by default took a width of 100%:

    width: 100%;

<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/></div>
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/></div>

Oops, not so good. It has now distributed the "table" cells across the 100% width "table" DIV and the images are completely separated.

So instead we use the automatic margin trick, which preserves the table-like DIV's width:

    margin-left: auto;
    margin-right: auto;

<img src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/></div>
<img src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/></div>

Phew ! All that just to vertically and horizontally center 2 images with "modern" CSS table-like DIV layout methods. But while the table-like DIV display/layout methods are very flexible (can handle many more cases than I am exploring here), for the simpler case of vertically (and horizontally) centering 2 images we can make it much easier, if we understand that (from Vertical Centering With CSS):

'There are a few ways to center vertically. In terms of block level elements, the methods are quirky. Inline elements are much simpler to center'

The whole effort with the 'display: table;' and 'display: table-cell;' approach above is because DIV is by default (otherwise) a block element. We can actually use vertical-align on inline elements like IMG directly, we don't even need a 'display: table-cell;' containing DIV.

Simpler: apply vertical-align directly to inline elements (like IMG) inside a DIV container

First lets look at it with a TABLE-like container DIV, but we'll leave out the middle-man, those table-cell-like DIVs that were wrapping the images:

<img class="CENTER MIDDLE BORDERED" src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/><img class="CENTER MIDDLE BORDERED" src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/>

The containing table-like DIV needs the automatic margins, because otherwise it will not center properly horizontally within the content area, because being now "table-like" it will only take up as much space as its "table" needs (see the border).

Note once again that, because I am using Drupal, I have to take care above not to put a newline between the end of one IMG and the next IMG, otherwise Drupal text filters will insert a <BR/>; this is not a problem with the 'display: table-cell;' DIV approach.

We can make it more compact still; simply let a containing DIV take up maximum width, let it center the 2 images horizontally, and let the 2 images "vertically align themselves" within the container:

<div class="CENTER BORDERED">
<img class="MIDDLE" src="http://www.webel.com.au/sites/default/files/images/demo/test-aurora.jpg"/><img class="MIDDLE" src="http://www.webel.com.au/sites/default/files/images/demo/test-einstein.jpg"/>

And it works with no reference to CSS table-like display modes anywhere.

So there you have it; the most compact horizontal and vertical centering form for 2 images possible. This is not the most flexible approach, sometimes the table-like DIV containers (TABLE/ROW/CELL) approach is needed, but often that approach is incorrectly shown as the "correct" way to use 'vertical-align', merely because people don't understand that vertical-align is basically intended for use with inline elements, and functions very differently from text-align (which aligns child elements within block elements). They sound similar, but work very differently !

Finally, the usually superb W3Schools CSS reference is (currently) a complete let-down when it comes to vertical-align. Although it gives an example using an IMG, it says nothing about the consequences for block vs inline elements, and if you took it literally 'The vertical-align property sets the vertical alignment of an element' you would be left very confused when applying it to other element types.

Make sure you also examine: CSS: on using DIVs for TABLE style formatting

Syndicate content