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:
- 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.
- 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.
- 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.
- 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:
- 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).
- 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.