Position: relative for <body>?

A while back I must have read or seen an example of using position: relative for the body of an HTML document:


body
{
   position: relative;
}

I have been doing this with no apparent problems on many of my pages. Just today I ran into a problem. Some JavaScript code that I’ve used for a long time on other pages no longer works properly when I make the body have position: relative. The JavaScript allows dragging and dropping items to new positions in a ul.

First, I don’t see the connection. But second, SHOULD I use position: relative for the body of ANY page? Are there any advantages to doing it? Are there any disadvantages (other than my particular JavaScript problem)?

Thanks.

Ken

Hi Ken, welcome to Sitepoint :slight_smile:

You shouldn’t use anything if you don’t know what it does :slight_smile:

If position: relative is not needed don’t use it, simple.

There are times when absolute positioning and there is no other parent to the absolute element, that you would want to set position:relative on the body (otherwise it will default to the viewport, aka <html>) but as markbrown4 said, unless you need it then lose it :slight_smile:

Hi,

You don’t need position:relative on the body unless you run into a bug where it can be used to cure a problem.

Adding position:relative to the body is a fix for ie5.x and IE in quirks mode when you use the body for centering.

e.g.


body{width:800px;margin:auto;position:relative;}


Without the position:relative it won’t work in those browsers. I always recommend not using the body element for centering anyway as it’s more trouble than it’s worth.

Indeed in the thread I took that snippet from the position;relative was killing the javascript in that page also.

In reality position:relative isn’t needed on the body at all because that is the viewport anyway and absolute elements will use this for their context by default.

Thanks so much for all the help–very informative, just what I needed.

One follow-up, Paul. You mentioned, “that snippet from the position;relative was killing the javascript in that page also.” Is it possible, without digging into specific JavaScript code, to explain the connection? Why would making the body “position: relative” effect the operation of the JavaScript?

Just curious–I’m always interested in learning more.

Ken

Technically, <html> is the initial containing block. If you don’t mess with <body>'s dimensions, they’re effectively equivalent. See §10.1 Definition of “containing block”.

Test case:

Things to note are the initial position of the AP block without declared offsets (the normal in-the-flow location), and its position when offsets are declared. Remove or comment the offsets for comparison. Also add body {position: relative;} with and without offsets in place. Notice that IE, Opera, and Google-chrome collapse the AP element’s margin contrary to to the specs.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="en-US"
      lang="en-US">
<head>
  <meta http-equiv="Content-Type"
        content="text/html; charset=utf-8" />

  <title>misc tests</title>
  <style type="text/css">
/*<![CDATA[*/
  body, html {
    margin: 0;
    padding: 0;
    font: 100% sans-serif;
    }

  html {
    background-color: magenta;
    }

  body {
    background-color: cyan;
    border: 1px solid black;
    margin: 0 auto;
    width: 50%;
    }

  p {
    border: 1px solid black;
    }

  p#b {
    background-color: yellow;
    position: absolute;
    left: 0px;
    top: 0px;
    }

  /*]]>*/
  </style>
</head>

<body>
  <p id="a">This is paragraph "a".</p>

  <p id="b">This is paragraph "b".</p>

  <p id="c">This is paragraph "c", made a bit longer for clarity.</p>
</body>
</html>

cheers,

gary

Yes that’s what I meant :slight_smile:

(I always recommend not using the body as a centred container anyway due to the numerous bugs in IE I linked to above.)

Notice that IE, Opera, and Google-chrome collapse the AP element’s margin contrary to to the specs

It’s strange that they can’t get this right and the reason I usually remove margins from absolute elements to avoid this issue.

Why would making the body “position: relative” effect the operation of the JavaScript?

Javascript isn’t my area but I’m guessing that a reference was needed from the viewport but when the body was given a width and position:relative added then all the offsets were miscalculated because they now refer to the centred portion (as shown in Gary’s demo.

However there may be a simpler explanation.:wink:

I don’t see the issue you speak of in Opera 10.5, IE8, nor Chrome 4.

If you’re referring to the issue in IE6/7, this isn’t an issue relating to the specification definition of margin collapsing (although it could be described using the expression ‘margin collapsing’ based on the actual result), since your test case doesn’t include any scenarios where the margin collapsing model could participate in the rendering of the absp element.

Instead, I’d suggest that the aforementioned browsers wrongly offset an absp element from that element’s border box as opposed to it’s margin box, therefore not taking into account any margin values.

I’m really appreciating all this help. At the risk of becoming tiresome, however, some new questions have been generated. Paul, you said this:

Javascript isn’t my area but I’m guessing that a reference was needed from the viewport but when the body was given a width and position:relative added then all the offsets were miscalculated because they now refer to the centred portion (as shown in Gary’s demo.

When I took the “position: relative” out of the body style rules, the JavaScript started working again, and there were no apparent side effects that I’ve noticed. But I still specify a width, and your comment here seemed to imply that maybe there might be a reason for not including width either. You also mentioned margins and centering as possible problems, which I also do in “body”! So I’ll just show you my entire declaration–which seems to be working–and ask for comments.


body
{
   /* position: relative; */
   width: 880px;
   margin-left: auto;
   margin-right: auto;
   color: black;
   background-color: #B0C4DE;
   text-align: left;
   font-size: 14px;
}

Thanks.

Ken

Hi Ken,

I believe Paul is recommending you move the margin and width to another element like a wrapping div. text-align: center on the body is also needed for archaic browsers. Here’s what I would do.


body {
   color: black;
   background-color: #B0C4DE;
   text-align: center;
   font-size: 14px;
}
#wrapper {
   width: 880px;
   margin: 0 auto;
   text-align: left;
}

If the javascript is a lightbox script or similiar it would be positioning things relative to that 880px box and not the viewport - it’s just best not to mess the body element unless you want to achieve something like 100% height layouts.

Hi,

Yes that will work as long as you don’t want to support ie5.x or any version of IE in quirks mode which isn’t such a big deal these days anyway.:slight_smile:

There are though a couple of things to watch out for.

In IE7 the zoom function doesn’t work properly when the body is centred and the zoom soon disappears off screen. Not a major problem but not right all the same.

The main problem is that now the position:relative is removed you would have to make sure that you set an inner stacking context for any absolutely positioned elements. This shouldn’t be a problem as you can place position:relative on an inner wrapper as a parent of the absolute element.

However, for the sake of one extra html element you can forego all these bugs and support older browsers as well.


body {
    color: black;
    background-color: #B0C4DE;
    text-align: center;
    font-size: 14px;
}
#wrap {
    width: 880px;
    margin: auto;
    text-align: left;/*position: relative; if needed*/
}


But you will probably be ok with your version :slight_smile:

Edit:

I should have refreshed before posting :slight_smile:

Thanks, Paul. Yes, things seem to be working, but I’m not sure why. I was aware of the point you made in your caution:

The main problem is that now the position:relative is removed you would have to make sure that you set an inner stacking context for any absolutely positioned elements. This shouldn’t be a problem as you can place position:relative on an inner wrapper as a parent of the absolute element.

I do have an element declared as position: absolute, and no parental element above it is positioned at all. The absolutely positioned element is a ul element that is part of my pop-down menu. The page has an always-visible horizontal menu (implemented as a table), and then I use JavaScript to make a pop-down sub-menu appear on mouseover. Here’s the CSS:


#Menu
{
   margin-bottom: 0px;
   border: 0px solid red;
}

table.menu
{
   width: 876px;
   margin-left: auto;
   margin-right: auto;
   border-spacing: 0px;
}

tr.menu
{
   background-color: #add8e6; /* Background color for horizontal menu */
   margin: 0px;
   padding: 0px;
}

td.menu
{
   border: 2px solid #000066; /* Border color for horizontal menu */
   padding: 2px;
   font-weight: bold;

   text-align: center;
   cursor: pointer;
}


ul.noShow
{
   visibility: hidden;
   position: absolute;

   list-style-type: none;
   margin: 0px;
   padding: 0px;
}


li.menu
{
   list-style-position: outside;

   background-color: #e6ffe5; /* Background color for pull-down menu */
   width: 190px;
   margin-top: 0px;
   margin-bottom: 0px;
   border: 2px solid #000066; /* Border color for pull-down menu */
   padding: 3px;
}

It still works fine. Why is it working?

Ken

Do this

Off Topic:

What was the point of that? :slight_smile:

keyboard broen

That last paragraph caused me to alter the case a bit. It now includes an obvious margin collapse scenario.

  p {
    border: 1px solid black;
    line-height: 1;
    margin: 1em 0;
    }

  p#b {
    background-color: yellow;
    margin: 1.5em 0;
    position: absolute;
    }

The spacing between p#a and p#b should be the sum of the vertical margins, 2.5em, as there is no offset to trigger the initial containing block issue; the AP container will appear in its natural position in the flow. If there is margin collapse, the spacing mentioned above will be the larger of 1em and 1.5em. This is true of Opera 10.10 and the current google-chrome, both in Linux. Firefox 3.5.6, also in Linux, and IE6 both exhibit a 2.5em spacing. IE6 has plenty of other margin weirdness to offset getting this particular bit correct. I do not have IE 7/8 available for testing at this time.

If I have some how skirted your point, please show us a more telling test case.

cheers,

gary

It works because there are no co-ordinates supplied for the absolute element. That means the absolute element becomes absolute at that exact point it happens to be in the mark up.

If you tried to move it with left:10px you would see that it would jump from where it was right over to the viewport.

As long as you don’t need to supply co-ordinates you should be ok but there is a bug in IE where if you set the text-alignment of a parent of the absolute element to anything but left then the absolute element gets shifted along with the text-align and would be mis-positioned when it has n co-ordinates.

This thread has certainly been helpful to me. I do have Eric Meyer’s book, CSS: The Definitive Guide (O’Reilly). It’s a well-written reference book, but a book can’t dig into every question raised by a particular application (such as a JavaScript-driven pop-down menu).

I have one more question, and I’m hoping I haven’t tried your patience beyond repair!

Paul, you wrote:

It works because there are no co-ordinates supplied for the absolute element. That means the absolute element becomes absolute at that exact point it happens to be in the mark up. If you tried to move it with left:10px you would see that it would jump from where it was right over to the viewport.

Yes, this makes sense to me. And I tried the suggested experiment, and it certainly does move the pop-down ul list from where it should open.

But the phrase that struck me was “becomes absolute.” What exactly is the essence of being “absolute”? Let me put the question in context. If I remove “position: absolute” from the above code, then the ul list–even though it is invisible before mouseover–forces the table holding the main horizontal menu to expand in height enough to contain the ul list, which of course makes it look ridiculous.

Why does making the ul list absolute prevent it from expanding the table?

Thank again.

Ken

It prevents the parent from expanding because hte parent doesn’t even recognize it is there. Absolute elements are removed from the flow of the document and as such the parent has no idea it is there (nor do other elements, even other absolutes!)

Thanks again to everyone. I think I understand what’s going on now.

By the way, what happened to the “edit” button? I have already edited one or two of my posts in this thread, but this morning when I wanted to reword one of my sentences in post 18, the “edit” button was gone!

Ken

Edit: Goodness! No sooner do I post this, but the edit button appears on it! Perhaps you can edit only until a reply has been made??? But then I had wanted to edit post 18 before Ryan made his reply. I’m confused (which is not too hard to do).