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:
  1. html,body{
  2.     height:100%;
  3.     margin:0;
  4.     padding:0;
  5. }
  6. body{
  7.     background:#eae7d7 url(images/vert-centre.jpg) repeat-x center center;
  8.     text-align:center;
  9.     min-width:626px;
  10.     min-height:400px;
  11. }
  12. #vert-hoz{
  13.     position:absolute;
  14.     top:50%;
  15.     left:50%;
  16.     margin-top:-198px;/* half elements height*/
  17.     margin-left:-313px;/* half elements width*/
  18.     width:624px;
  19.     height:394px;
  20.     border:1px solid silver;
  21.     background:#666;
  22.     overflow:auto;/* allow content to scroll inside element */
  23.     text-align:left;
  24. }
  25. h1 {color:#fff;margin:0;padding:0}

HTML:
  1. <div id="vert-hoz">
  2.     <h1>Content goes here</h1>
  3. </div>

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:
  1. html,body{
  2.     height:100%;
  3.     margin:0;
  4.     padding:0;
  5. }
  6. body{
  7.     background:#eae7d7 url(images/vert-centre.jpg) repeat-x center center;
  8.     text-align:center;
  9.     min-width:626px;
  10.     min-height:400px;
  11. }
  12. #vertical{
  13.     position:absolute;
  14.     top:50%;
  15.     margin-top:-198px;/* half main elements height*/
  16.     left:0;
  17.     width:100%;
  18. }
  19. #hoz {
  20.     width:624px;
  21.     margin-left:auto;
  22.     margin-right:auto;
  23.     height:394px;
  24.     border:1px solid silver;
  25.     background:#666;
  26.     overflow:auto;/* allow content to scroll inside element */
  27.     text-align:left;
  28. }
  29. h1 {color:#fff;margin:0;padding:0}

HTML:
  1. <div id="vertical">
  2.     <div id="hoz">
  3.         <h1>Content goes here</h1>
  4.     </div>
  5. </div>

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:
  1. #vertical{
  2.     float:left;
  3.     height:50%;
  4.     margin-top:-198px;/* half vertical height*/
  5.     width:100%;
  6. }

HTML:
  1. <div id="vertical"></div>
  2. <div id="hoz">
  3.     <h1>Content goes here</h1>
  4. </div>

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.

CSS:
  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. }

HTML:
  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.

CSS:
  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?

CSS:
  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!

30 Responses to “Easy Vertical Centering with CSS”

1 John

Nicely explained and illustrated Paul. :)

2 Paul OB

Thanks John :)

3  

Very nice and thorough!

also add fixed bg positioning to bg body image to prevent vertical scrolling when low browser height.

background:#eae7d7 url(images/vert-centre.jpg) repeat-x center center fixed;

4 Joe Banner

Excellent idea and a solution to something that’s kept me stumped for ages. Thank you!

On an unrelated note, you might be interested in the fireshot extension for Firefox (http://screenshot-program.com/fireshot/). It takes snapshots of your browser window (just page content, not the toolbars) and saves them - or if you prefer copies them to the clipboard / opens them in editor of choice etc. Should save you a bit of time mashing the print-screen button!

5 Golgotha

Paul, you really are a mad scientist when it comes to CSS.

6 Paul OB

Thanks for the link Joe - looks useful :)

[...] Easy Vertical Centering with CSS Related StuffTop reasons your CSS columns are messed up How To: Resizeable Background Image8 fonts you probably don’t use in css, but should47+ Excellent Ajax CSS FormsHow to create a Dock MenuBush CSSLearning CSS For BeginnersFive Free CSS Sliding Door Tab Menus | Blog.SpoonGraphics23 Resources for Clean and Compressed CSSHomer Simpson CSS [...]

8 links for 2008-05-17 | iKeif

[...] Easy Vertical Centering with CSS 21 hours agoCSS never ceases to amaze me.A Letter to My Son, on Starting Out In Life | Zen Habits [...]

9 Chaim

Interesting!

10 Najlepsze Ogłoszenia

Thanks for very interesting article. I really enjoyed reading all of your articles. Keep up the good work. See You

11 Wii Fit Accessories

Wow… this is going to help me out so much. I had tried multiple methods and I tried searching, to no avail. I finally came across your post, and I am so glad that i did. Thanks.

12 świr

very nice and clearly explained, thanks a lot.

13 links for 2008-06-06 at found_drama

[...] Easy Vertical Centering with CSS (tags: CSS html tutorial webdev work todo) [...]

14 links for 2008-06-06 « Donghai Ma

[...] Easy Vertical Centering with CSS (tags: computer webdev webdesign design tips) [...]

15 Missy

If only this worked for variable height content, not fixed-height blocks.

[...] Visit Tutorial [...]

17 Paul OB

Hi Missy,

You’d need a more complicated method such as the following to centre elements of unknown width and height.

http://www.pmob.co.uk/pob/vertical-center1.htm

18 Liens du jour - Barbablog

[...] Easy Vertical Centering with CSS (tags: alignment css float centering webdesign vertical horizontal) [...]

[...] Easy Vertical Centering with CSS [...]

20 Oliver Kiss

Nice examples!

21 Mariusz

That’s a good technique, but it’s never-ever gonna validate as Strict due to empty div.

22 Jacco

LOL this page has multiple H1 tags. Ever heard about semantics??

23 Oguzhan

CSS is inferior for vertical alignment. There must something like valign that used for tables.

24 Stephen R

This line:
margin-top:-198px;/* half vertical height*/

Doesn’t this require knowing the elements height. What if that element changed? Would this still work?

25 Dot Mike

Thank you so much–you are truly a great benefactor to all designers.

I’ve been hacking around in you excellent code trying to figure out how to float the content not dead V center, but at like 33% from the top which has a definite grace.

The 33% is easy, but getting the top margin to shrink at a ratio is where I’m stuck. Right now the top of my container hits the top of the browser window way before the bottom of the window hits the bottom of the container.

I’m going to keep hacking at it and see if I luck into a solution, but you are the master so I thought I’d throw the problem out there.

Again, thanks so much. You totally rule.

26 Michael

I agree with Stephen R.

Show me how this can be resized and I will be impressed.

mc

27 Egypt Web Design

Woww! Thanks for sharing your information.

[...] Vertical Centering with CSS [...]

29 cssmake

nice text. thanks

30 Egypt Web Designe

thanks nice information.

Share your thoughts...

WordPress Plugins

Blog Categories

Meta

Add this blog to my Technorati Favorites!

Popular Articles

Top 10 Commentators


Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Blogs Worth Reading