Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Position:fixed element within a position:relative parent. Which browser renders correctly?

I am seeing a discrepancy in how fixed position elements behave within a relatively positioned parent. According to the docs I am finding online, FireFox and Chrome should fix the element to the viewport and not the parent. However, I am finding that if I do not specify a left/right value on a fixed element, it behaves in a sort of mix between static AND fixed, in the sense that it's fixed vertically to the viewport, but moves as if it were a static element within the parent element. I can't find any official/respected documentation surrounding these conditions. They all basically state something like the following:

Fixed Positioning Do not leave space for the element. Instead, position it at a specified position relative to the screen's viewport and don't move it when scrolled. When printing, position it at that fixed position on every page.

Source

Safari on the other hand, seems to render it as it is described where it's fixed purely to the viewport, no matter if I set a parent element to relative without any top/right/bottom/left properties defined. Try it out in Safari if you have a chance by clicking on the teal div which positions it -100 pixels from the left. The yellow bar will stay fixed to the viewport:

http://jsfiddle.net/bbL8Lh4r/2/

So which browser is rendering this correctly? All my browsers have been updated to the latest. At first I thought Safari was the right one just by reading the docs, but FireFox and Chrome both share the same different view where it seems to be a hybrid between static and fixed.


HTML

<body>
    <aside>
        Blah
    </aside>

    <div class="container">
        <div class="nav">
            BLARGH
        </div>
    </div>
</body>

CSS

body,
aside,
.container,
.nav {
    margin:0;
    padding:0;
}

aside {
    background:red;
    width:30%;
    height:800px;
    float:left;
}

.container {
    position:relative;
    height:800px;
    width:70%;
    background:teal;
    float:right;
}

.container.stickied {
    left:-100px;
}

.container .nav {
    position:fixed;
    background:yellow;
    width:inherit;
}
like image 978
Kerry Johnson Avatar asked Feb 18 '15 04:02

Kerry Johnson


People also ask

How do you position a fixed relative to a parent?

To position an element "fixed" relative to a parent element, you want position:absolute on the child element, and any position mode other than the default or static on your parent element. This will position childDiv element 50 pixels left and 20 pixels down relative to parentDiv's position.

What position element is used to position an element relative to its parent element?

Absolute In position: relative , the element is positioned relative to itself. However, an absolutely positioned element is relative to its parent. An element with position: absolute is removed from the normal document flow. It is positioned automatically to the starting point (top-left corner) of its parent element.

When using position fixed What will the element always be positioned relative to?

An element with position: fixed; is positioned relative to the viewport, which means it always stays in the same place even if the page is scrolled. The top, right, bottom, and left properties are used to position the element.

Which of the following position property values positions an element relative to the browser window?

A fixed position element is positioned relative to the viewport, or the browser window itself.


1 Answers

This appears to be an interesting case. Let's take a deep dive into the specifications to find out what's going on.


TL;DR: The W3 specification is critically vague/undefined in this area, but it appears that all browsers deviate from the spec, or at least, they made a decision where details were undefined. However, four of the major browsers (Firefox, Chrome, IE, and Opera) are united in that they all seem to deviate from the spec in the same way. Safari is definitely the odd man out here.


This is what the CSS2.1 spec has to say in Chapter 9: Visual formatting model:

  1. 9.1.2 Containing blocks - In CSS 2.1, many box positions and sizes are calculated with respect to the edges of a rectangular box called a containing block. In general, generated boxes act as containing blocks for descendant boxes; we say that a box "establishes" the containing block for its descendants. The phrase "a box's containing block" means "the containing block in which the box lives," not the one it generates.

This just defines what a containing block is.

  1. 9.3 Positioning Schemes - Absolute positioning: In the absolute positioning model, a box is removed from the normal flow entirely and assigned a position with respect to a containing block.

This says absolutely positioned elements are positioned with respect to a containing block.

  1. 9.6 Absolute Positioning - In the absolute positioning model, a box is explicitly offset with respect to its containing block. [...] References in this specification to an absolutely positioned element (or its box) imply that the element's position property has the value absolute or fixed.

This says absolutely positioned elements include position:fixed; elements as well as position: absolute; elements.

  1. 9.6.1 Fixed Positioning - Fixed positioning is a subcategory of absolute positioning. The only difference is that for a fixed position box, the containing block is established by the viewport.

And this says position: fixed; elements have the Viewport (well, not literally the viewport, but a box with the same dimensions and positions as the viewport) as their containing box. This is backed up later by the spec in 10.1 Definition of containing block:

If the element has 'position: fixed', the containing block is established by the viewport [...]

(If you aren't familiar with what the viewport is, it is "a window or other viewing area on the screen through which users consult a document". The viewport's dimensions are the basis for the initial containing block. The entirety of your HTML content (<html>, <body>, etc.) resides within this initial containing block defined by the viewport.)

Therefore, the <div class="nav"> element with position: fixed; applied to it should have a containing block equal to the Viewport, or the initial containing block.


Now that the first step of determining the properties of the .nav element is complete, we can determine how the browsers are supposed to behave.

The CSS2.1 spec has this to say:

  1. 9.7 Relationships between 'display', 'position', and 'float' - Otherwise, if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned, the computed value of 'float' is 'none', and display is set according to the table below. The position of the box will be determined by the 'top', 'right', 'bottom' and 'left' properties and the box's containing block.

This is basically telling us that, for absolutely positioned elements (position: fixed; or position: absolute;), any float properties are ignored, that <div> elements (among others) are set to display: block;, and that the element is positioned according to its box offset values of top, right, bottom, and/or left in combination with the initial containing block (the viewport).

  1. 9.3.2 Box offsets: 'top', 'right', 'bottom', 'left' - An element is said to be positioned if its 'position' property has a value other than 'static'. Positioned elements generate positioned boxes, laid out according to four properties: top, right, bottom, left.

This just reaffirms the fact that <div class="nav"> should be positioned according to its box offsets.

Although it says in several places that if two opposing offset values are auto, then they are set to zero, CSS2.1 doesn't seem to specify the case for how to position elements with both left and right values of zero. CSS Box Alignment Module Level 3, however, does mention that the value is set to "start", which is defined as:

Aligns the alignment subject to be flush with the alignment container’s start edge.

This should mean the element is positioned at the top-left of the containing block, which, for position: fixed; elements, should be the same as the viewport. However, we can see that, for all major browsers, this is not the case. None of the major browsers seem to be setting the position: fixed;'s containing block to that of the viewport as instructed by the spec. Instead, they are all acting as if behavior should be identical between position: fixed; and position: absolute;.

In summation, when you have this much evidence in the spec's own words, the answer is clear: position: fixed; elements should have a containing block set to the viewport. What's also clear is that the vendors have all decided to fill-in a vague part of the spec in their own way, conflicting with, or outright ignoring this declaration. What is most likely to have happened is that one browser implemented their interpretation (IE7 was the first to support position: fixed;, I believe, followed shortly by Firefox 2.0) and the rest followed.

like image 178
TylerH Avatar answered Nov 15 '22 21:11

TylerH