Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
767 views
in Technique[技术] by (71.8m points)

html - 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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...