Why does overflow-x: hidden make my absolutely positioned element fixed?

I am trying to understand why setting overflow-x: hidden in the body of an HTML page makes my position: fixed element even if I set it to position: absolute .

The effect is better understood in this demo .

Here is the code:

HTML:

 <div class='background'></div> <div class='page'></div> <div class='page'></div> <div class='page'></div> <div class='page'></div> 

CSS

 html, body { width: 100%; height: 100%; padding: 0; margin: 0; overflow-x: hidden; /* If I remove this line everything is how I expect it to be! */ } div.page { positon: relative; width: 100%; height: 100%; min-height: 100%; border: 1px solid red; margin-bottom:200px; } div.background { background: blue; position: absolute; width: 100%; height: 20%; } 

Question

What is the relationship between overflow-x: hidden and positioning? Why does setting this property cause my element to become position: fixed instead of position: absolute ?

+4
html css
Feb 05 '13 at 22:36
source share
2 answers

The element is still position: absolute , but it seems to be fixed thanks to some rather complex interactions between position , overflow and the window model. Incredibly, none of these types of behavior is indicated or an error in any browser - it is actually completely in design if it is a little counter-intuitive.

It basically boils down to the following:

  • An absolutely positioned element is tied to the viewport if none of its ancestors is placed. (This is why adding position: relative to the body works as suggested in another answer .)

  • You have width: 100%; height: 100%; width: 100%; height: 100%; for both html and body; this prevents the viewport from expanding beyond the visible area, so the viewport never scrolls.

  • Since the viewport does not scroll, it does not have an absolutely positioned element. This makes it appear fixed even if the rest of the page scrolls.

Oddly enough, this also works on IE6 .




More detailed explanation:

  • An absolutely positioned element is tied to the viewport if none of its ancestors is placed.

    The spec in the overflow property, which, incidentally, contains another example of the same problem that you are observing, where an element with overflow: scroll interacts with an absolutely positioned descendant element, states the following:

    This property determines whether the contents of a block container element are clipped when it overflows the element field. This affects the clipping of the entire content of the element, with the exception of any descendant elements (and their corresponding contents and descendants) whose containing block is the viewport or ancestor of the element.

    Your absolutely positioned element is a descendant whose containing block is the viewport (also containing the html element block), since both html and body are not located. This corresponds to another section of the specification . This prevents excessive trimming on the html and body from any effect on your absolutely positioned element, since it is tied to the viewport.

  • You have width: 100%; height: 100%; width: 100%; height: 100%; for both html and body; this prevents the viewport from expanding beyond the visible area, so the viewport never scrolls.

    Then the specification states the following, later in the same section:

    UAs must apply the overflow property in the root element to the viewport. When the root element is an HTML HTML element or an XHTML html element and that element has a BODY HTML element or an XHTML body element as a child element, user agents should instead use the overflow property from the first such child element to the viewport if the value in the root element is "visible." The value “visible” when used for the viewport should be interpreted as “auto”. The element from which the value extends must have the value used to overflow the visible.

    Simply put:

    • If the html is not overflow: visible , apply it to the viewport instead and change the html to overflow: visible . The overflow value given to the body does not change.

    • If html is overflow: visible , but the body is not, apply it to the viewport and return the body to overflow: visible .

    (Setting overflow-x or overflow-y to anything other than visible for an element causes the overflow transcript to no longer be visible for that element .)

    This usually means that the viewport should scroll naturally with the html and body, since only one scroll bar should exist at a time.

    However ... you also give both html and body 100% width and height! This means 100% more than its container. The body container is html, and the html container is the viewport. But since you cannot use CSS to control the size of the viewport, which is completely handled by the browser, you are left with two elements that are limited to 100% the height of the visible part of the viewer window (also known as the fold). The viewport itself should not expand beyond the fold, since not one of its contents requires more space than is visible (note that absolutely positioned elements are never taken into account). Thus, the viewport does not create a scroll bar (and does not html); The scroll bar that you see belongs to the body.

    If you did not set the width or height properties, they would be auto by default, causing both the html and the body to expand with their contents and always be the same size as the entire area of ​​the viewport, including the area below the folds. This prevents the body from creating a scroll bar because it will always stretch to fit its contents, so you only see the scroll bar in the viewport, and the absolutely positioned element will scroll along with the rest of the page.

  • Since the viewport does not scroll, it does not have an absolutely positioned element. This makes it appear fixed even if the rest of the page scrolls.

    What happens when you scroll is that you really scroll the body element. Since an absolutely positioned element is tied to a viewport that never scrolls, it seems to be fixed, rather than scrolling.

    By the way, this is also why the element seems to overlap the scroll bar when it doesn't scroll at all. The scrollbar belongs to the body, which is located under an absolutely positioned element. If you remove the overflow-x declaration or the width and height declarations from the html and body, the scroll bar that you see will appear instead. However, if you position the body, the scrollbar still belongs to the body, but the element also becomes a child of the body, so it will not overlap the scrollbar.

+21
Feb 06 '13 at 23:03
source share

You need to add position: relative to the body . Your div.background has position: absolute , which forces it to stick to the top of the HTML document. If you do not want this, you need to provide its parent (in this case, body tag) position: relative .

DEMO # 1: http://tinkerbin.com/nmI74RpC

Alternatively, you can remove position: absolute from div.background , but I'm not sure how this will affect the rest of your layout.

DEMO # 2: http://tinkerbin.com/PP5PpbuC

+3
Feb 05 '13 at 22:50
source share



All Articles