May 15th, 2008 - by Paul OB

It’s always good when you learn something that you already knew isn’t it?

I know that probably doesn’t quite make sense but what I mean is that quite often you know how things work but it’s how they are applied that can make all the difference. This is the beauty with CSS where you can always be surprised at the different ways the same layout can be achieved. This happened to me the other week when I noticed a different way that a site had been centered using simple techniques already known to us all. Indeed, many of you may already have used this method but it seems to have escaped my attention until now.

The Old Way

One of the first things I learned to do in CSS was how to horizontally and vertically center a fixed width and height element. This could be an image for a splash page (god forbid) or a small centered site that some designers love to do. Originally this was accomplished with absolutely positioning an element 50% from the top and 50% from the left of the viewport. This of course only places the top left corner of the element at the center of the viewport and you then need to drag the element back into a central position with a negative margin equal to half the height and half the width of the element.

Let’s take a look at the old way of doing this and note what the problems are.

[CSS]
html,body{
height:100%;
margin:0;
padding:0;
}
body{
background:#eae7d7 url(images/vert-centre.jpg) repeat-x center center;
text-align:center;
min-width:626px;
min-height:400px;
}
#vert-hoz{
position:absolute;
top:50%;
left:50%;
margin-top:-198px;/* half elements height*/
margin-left:-313px;/* half elements width*/
width:624px;
height:394px;
border:1px solid silver;
background:#666;
overflow:auto;/* allow content to scroll inside element */
text-align:left;
}
h1 {color:#fff;margin:0;padding:0}
[/CSS]

[HTML]

Content goes here

[/HTML]

A live version can be found here and the result as shown in the Figure 1 below.

Figure 1

I have added a background image to the body just to make the page look nice so the only part we are really interested in here is the gray centered portion. (As an aside you should note that to get the background image centered in the viewport you need to set html,body to be 100% high.)

As you can see the result is what we wanted and the element is perfectly centered both horizontally and vertically. This is achieved as already mentioned by putting the top left corner of the element at 50% from the top and 50% from the left. Then using a negative top margin and a negative left margin the element is pulled into a central position using half the elements’ height and half the elements’ width for the appropriate negative margins.

Although at first glance this seems to work well, there are some severe downsides to using this method and they can be seen by closing the browser window both horizontally and vertically. As the window gets smaller than the element’s size the element starts sliding out of view at both the top of the window and the left side of the window. The areas that have slid outside the window are now in fact unreachable even by using the scrollbars on the window. This would mean that users with small screen sizes could not access the content at all.

Figure 2 shows what has happened to the one line of text from our example when the window is closed smaller.

Figure 2

The text is half missing at the top and has also disappeared to the left. If we closed the window further the text would disappear completely. In order to try and address these issues a min-height and min-width has been added to the body, but as you can see this has had no effect at all and the element still lies outside the viewport.

Revised Method

In light of these problems another similar version of this centering technique can be used where the element is still placed absolutely from the top but this time the horizontal centering is achieved using auto margins. This also eliminates the element from sliding off the left of the window.

Here is the revised code.
[CSS]
html,body{
height:100%;
margin:0;
padding:0;
}
body{
background:#eae7d7 url(images/vert-centre.jpg) repeat-x center center;
text-align:center;
min-width:626px;
min-height:400px;
}
#vertical{
position:absolute;
top:50%;
margin-top:-198px;/* half main elements height*/
left:0;
width:100%;
}
#hoz {
width:624px;
margin-left:auto;
margin-right:auto;
height:394px;
border:1px solid silver;
background:#666;
overflow:auto;/* allow content to scroll inside element */
text-align:left;
}
h1 {color:#fff;margin:0;padding:0}

[/css]

[HTML]

Content goes here

[/HTML]

A live version can be found here.

This has the desired effect horizontally but still leaves the top disappearing upwards when the height of the window is made smaller as shown in Figure 3.

Figure 3

The Fix

Now to get over this problem (and to get to the point of this post) I have previously used more complicated methods but there is a simpler, more robust solution involving a float instead of the absolute element.

The first element on the page is a float that is set at 50% of the height of the page. Then we drag the float upward by half the height of the element we want centered.

Here are the changes needed:

[CSS]
#vertical{
float:left;
height:50%;
margin-top:-198px;/* half vertical height*/
width:100%;
}
[/CSS]

[HTML]

Content goes here

[/HTML]

Here is the link to a live version so you can see for yourself.

Figure 4

The important part is that we use a float of 100% width and then also remember to add clear:both to the following element as some browsers will get confused otherwise. If we did not use “float” then the element would still be centred but it would also disappear through the top of the screen unlike the floated method.

Why This Works

This throws up an interesting behavior concerning floats and it’s good to understand what’s going on here exactly. Why is it that when we use a static element (or an absolute element as in the first example) that the content disappears through the top of the viewport but doesn’t do this with a float?

The nature of floats is that they are removed from the flow (although you can regain control by using “clear” on following elements). The content following a float is displaced to make room for the float (usually by the browser increasing the top margin on the static content to clear the float). If the float were not there at all then the content would occupy its normal position in the page. Therefore when using a negative top margin on a float, the float will travel outside the confines of any containing block because as we stated previously a float is basically removed from the flow. However if we drag the float far enough outside the containing block so that none of it exists inside, then any following content cannot continue to follow the float upwards but resides inside its containing block allowing the float to float way.

This is in fact what happens in our example as the float is dragged upwards away from the body and the following content has to remain inside the containing block formed by the body element. This may be a little hard to understand straight away but can be seen in a simple demo as follows.

  1. .float{
  2.     width:200px;
  3.     height:100px;
  4.     background:red;
  5.     float:left;
  6. }
  7. .top{
  8.     background:green;
  9.     height:300px;
  10.     width:100%;
  11. }
  12. .follow-on{
  13.     clear:both;
  14.     background:blue;
  15.     height:100px
  16. }
  1. <div class="top">Top</div>
  2. <div class="float">Float</div>
  3. <div class="follow-on">Following content</div>

The code above sets a static element at the top of the page followed by a float and then followed by more static content which produces the result seen in figure 5 below and in a live example here.

Figure 5

Nothing special there and all working as expected.

If we next add a 100px negative top margin to the float we get the result as shown in Figure 6.

  1. .float{
  2.     width:200px;
  3.     height:100px;
  4.     background:red;
  5.     float:left;
  6.     margin-top:-100px
  7. }

Figure 6

Still everything as expected but what happens if we increase the negative top margin to 200px?

  1. .float{
  2.     width:200px;
  3.     height:100px;
  4.     background:red;
  5.     float:left;
  6.     margin-top:-200px
  7. }

Figure 7 shows the result once again.

Figure 7

As you can see the float has moved away from the following content but the content that was below the float stays at the top of its own containing block (i.e. beneath the green block). This is exactly what happens when we drag the float outside the viewport in our main example.

However if we were to simply remove the float property from our red div then both the red div and the content below would be dragged up over the green element.

Figure 8

With a static element the flow of the page under the element with the negative margin is changed and all the content is dragged upwards accordingly.

I hope you have enjoyed this little tip (even if you already knew about it) and it shows that there is always something new to learn for all of us. Refer to the original example for the full source code as it is all in the head to be grabbed easily.

If you want to look at some more advanced centering techniques then I have a few other methods documented here. Have Fun!

73 Responses to “Easy Vertical Centering with CSS”

1 Tom Key

Thanx,
you are genial :-)
I needet right this one for new site of my rock band, with using Lightwindow script simultaneously. Only this solution is fully function – in another case, after quitting Lightwindow box, the centered content jump up, for unknown reason…
Many thanx once again,
TK

2 Jakob G

Hello Paul. Impressive work but it’s simply to complicated for me. I’ll continue using the valign tag in plain HTML. But do you know if vertical alignment will ever be implemented in CSS? I really don’t understand why the old farts at W3C don’t do something about this. We all want it! So what’s the problem?

3 Paul OB

Hi Jakob,

Thanks for your comments.

There is already an equivalent in css to the deprecated “valign” atttribute (it’s not a tag ;)) and is simply the “vertical-align” property.

It works in exactly the same way as valign and will vertically align the content in a table-cell (or inline elements in a single line).

There is no need to use the deprecated valign attribute when using tables at all.

Don’tconfuse table behaviour with the behaviour of other block elements as valign does not apply to non-table block elements either so in reality there can be no comparisons.

Yes it would be nice to have an easy vertical align property for block elements which is what I think you are asking. there are explorative specs at the w3c about ways to do this.
http://www.css3.info/advanced-layout-module-gets-a-refresh/
http://www.w3.org/TR/2005/WD-css3-layout-20051215/#vertical

It is possible to vertically align block elements now by setting an element to display:table/cell (which ie8 supports) and then using the vertical align property. (Opera/Firefox and Safari all support this now also).

Re the original article you mention that the solution here is too complicated but the html is actually less code than using a table to do the same thing so I don’t see a problem.:)

4 Ian

This is a very nice solution to vertical centering. But… when I add a link to view a site made this way set as blank and IE opens it as a new window and that window is small and the user expands the window it goes all wrong… hoz and ver scroll bar appear and content gets pushed down.

Any ideas how to fix this?

5 Paul OB

Hi Ian,

You’ll have to show me an example so I can see what’s happening. Post a link if you can

You shouldn’t really be opening new resized windows anyway (if that’s what you were doing) as it should be the users choice and not yours.

6 Ian

Hi Paul,

I agree you shouldn’t open a new window but many links do.

I used the vert hoz solution “http://www.pmob.co.uk/pob/hoz-vert-center.htm” and that works fine as a pop up.

I trashed the folders from the example but will remake for you to see.

7 Paul OB

Hi Ian,

Yes if you have a link I’ll take a look. I don’t see why it should not work in a small pop up window (but of course IE is always buggy at the best of times).

8 Sylwester w Górach

well i like this centering and now i found out why mny ppl said that i have bugs on my web site :) i just used old way to do it 😛

Thank you

9 Paul OB

@Sylwester: That would be your code that’s broken and not mine.

Please do no post inane comments without backing them up.

Thank you.

10 Paul OB

@Sylwester: Apologies for the above post I think I misunderstood what you were trying to say :)

11 semicodin

Paul . . . your tutorials are awesome. I however need to vertically center an IMAGE. Right now on the site I just got yesterday Explorer 6 is just crapping on my lovely little vertical alignment CSS (which shows up fine in Firefox what else is new). Just to completely take a dump on my layout scheme, Explorer also ignores the transparency of the gif I want to center — just covering all bases (won’t valign and compromises the background image).

Do you have cross-browser-friendly (non Javascript I beg of you lol) tutorials for images? Thanks Paul. You are ubiquitous!

semicodin

12 Paul OB

Hi Semicodin,

It depends on the context you have and where you want it centred exactly. If it was centred in the browser window like above then you could use the same method as above.

If it’s being centred in another div then it depends on how the page is constructed.

You can centre images vertically like this:

http://www.pmob.co.uk/temp/image-overflow3.htm
http://www.pmob.co.uk/temp/celltest2.htm
http://www.pmob.co.uk/temp/vertical-align11.htm
http://www.pmob.co.uk/temp/vertical-align3.htm

I’d probably need to see your page to see which is best.

13 Juju

Thank you very much! You solved my problem very well! So thanks allot!

Greetings from SWE

14 biscuit

really appreciate the explanation… using it on a site and it seems to work across the browsers i’ve checked so far (Chrome, Safari, FF, IE8, IE7)… thanks!

15 maosmurf

finally, you saved my life!
I was loking for such a solution for days. the “float-idea” is great!

thank you very very much 😉

16 MikeF

Wow, so much simpler and more effective than the other methods I have found. Not something that I even thought about until I needed it. Great to find such a brilliant explanation. Thanks so much

17 Kenny Fix

Rare that i bother to leave any comment… i usually grab what i need and run, but this explanation is spot on… big thanks to the nice man with the #vertical plan!

18 Paul OB

Thanks Kenny :)

19 Jeremy

Well, it’s been a year since the last comment, but I’ll take a shot. This works great, of course, but I’m desperately trying to float a logo OUTSIDE the centered container that will lock to the top left of the container and disappear offscreen before the content when the window is compressed.

I’ve achieved this using a different centering CSS method, but I much prefer this one if I can get the same result.

20 Paul OB

Hi Jeremy,

You should be able to do that quite easily.

Just drag our element upwards from inside the container.
.logo {
width:200px;
height:100px;
background:red;
margin:-110px 0 0;
float:left;
}

You will have to remove the overflow from #hoz or it won’t show. If you need to have scrollable content in the middle then you will need to nest an inner div and apply the overflow to that instead leaving the logo outside of that div.

21 Jeremy

Thanks so much. I had tried that and everything else I could think of, but it was the #hoz overflow that I was missing.

22 hestroy

Great work, man. Thanx!

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators


Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

Blogs Worth Reading