5

If I make a div (at the top of the page) have a margin-top: 10px, then an absolutely positioned div (that is on a higher z-index and outside that div and outside that div's parent) starts not at top: 0px but at 10px!

http://jsfiddle.net/afv3gze7/

Why is this? Simply removing the position: relative on the body fixes everything (but causes problems with other things in my code - I need the body positioned relatively).

http://jsfiddle.net/afv3gze7/1/

Problem Code:

<!DOCTYPE html>
<html>
    <head>
        <style>
            html
            {
                position: relative;
                min-width: 100%;
                height: 100%;
                min-height:100%;
            }

            body
            {
                min-width: 100%;
                min-height:100%;
                font-size: 100%;
            }
            .outer
            {
                position: relative;
                top: 0em;
                left: 0em;
                width: 100%;
                height: 100%;
                background-color: #ffffff;
            }

            .overlay
            {
                position: absolute;
                top: 0px;
                left: 0em;
                width: 100%;
                height: 100%;
                background-color: #000000;
                -moz-opacity: 0.50;
                -khtml-opacity: 0.50;
                -webkit-opacity: 0.50;
                opacity: 0.50;
                -ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=50);
                filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
                filter:alpha(opacity=50);
                z-index: 6;
                display: none;
            }

            .inner
            {
                position: relative;
                width: 100%;
                border: none;
                margin: 0em;
                padding: 0em;
                margin-top: 3.875em;
                overflow: hidden;
                z-index: 0;
            }
        </style>
    </head>
    <body>
        <div class="outer">
            <div class="inner">s</div>
        </div>
        <div class="overlay" style="display: block;"></div>
    </body>
</html>
Don Rhummy
  • 24,730
  • 42
  • 175
  • 330
  • Because absolutely positioned elements are positioned with respect to their closest positioned ancestor. – j08691 Sep 05 '14 at 19:27
  • 1
    But @j08691 the closest positioned ancestor is body. – Cool Blue Sep 06 '14 at 05:52
  • 4
    Possible duplicate of [Why doesn't \`top: 0\` work on absolutely positioned element relative to body?](http://stackoverflow.com/questions/33594788/why-doesnt-top-0-work-on-absolutely-positioned-element-relative-to-body) – Michael Benjamin Nov 09 '15 at 05:07
  • @Michael_B How is my question which was asked over a year ago, a duplicate of a question asked yesterday? It would be the other way around. – Don Rhummy Nov 09 '15 at 19:14
  • 1
    If you go through the answers to this question, you'll find that none of them provide an explanation for why the absolutely positioned div starts lower. @CoolBlue gets it right: *None of the answers seem to explain this behaviour for an asolutely positioned element relative to body.* ... The duplicate, however, provides a clear and complete explanation, plus other valuable insights. It wouldn't be helpful to users to forward to this version of the question. – Michael Benjamin Nov 09 '15 at 19:21

3 Answers3

1

This is what position: relative in CSS does. It moves the element from where it would normally render and leaves the space that it would normally occupy there. Here is more about relative positioning.

If you must keep position: relative on the body element, change the margin-top property on the .inner class to padding-top:

.inner
{
  position: relative;
  width: 100%;
  border: none;
  margin: 0em;
  padding: 0em;
  /*margin-top: 3.875em;*/
  padding-top: 3.875em;
  overflow: hidden;
  z-index: 0;
}
Matt Smith
  • 1,932
  • 1
  • 21
  • 41
  • The values given to `top` and `left` are `0em`, while `bottom` and `right` are not set at all. The relatively positioned element won't be moved at all. – Quentin Sep 05 '14 at 19:33
  • Changing to `padding-top` fixed the problem! Thanks. – Don Rhummy Sep 05 '14 at 19:44
  • But the problem element - overlay - is NOT relatively positioned. It seems like the margin of body is "reverse-inheriting" the top margin of inner. This seems wrong. Another way to fix the problem is to add invisible content to outer. This shakes the CSS engine out of its confusion and forces it to behave correctly. – Cool Blue Sep 06 '14 at 05:57
1

Setting position: relative (or any other positioning value that isn't static) establishes a new positioning context.

The absolutely positioned descendants will be positioned with respect to the relatively positioned element's edges instead of those of the window.

Since the body element has, by default, non-zero margin and/or padding, the top of .outer is lower so any absolutely positioned element inside it will be too.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
1

But the problem element (overlay) is absolutely positioned, not relatively. And it's positioning context is body. If you set margin and padding in body to zero, the problem persists. The overlay element should be positioned at top: 0 and left: 0 relative to the content box of body... and it isn't.

If you add any content to outer, for example...

.outer:before{
    content: 'outer';
    visibility: hidden;
}

Then it fixes the problem. It is also fixed if you add a border to outer, for example...

border: 1px solid transparent;

Fiddle

None of the answers seem to explain this behaviour for an asolutely positioned element relative to body.

EDIT: the problem is also collapsed by setting the padding of body to 1px...

body{
    padding-top: 1px;
}

Or, by setting a border for body...

body{
    border: 1px solid transparent;
}
Cool Blue
  • 6,438
  • 6
  • 29
  • 68