6

Given:

   <body>
     <div id="fixed">
       Fixed div
     </div>
     <div id="nonfixed">
       <p>Non-fixed div</p>
       <p>Non-fixed div</p>
       <p>Non-fixed div</p>
     </div>
 </body>

And:

* { box-sizing: border-box; }

body {
    margin: 0;
    padding: 0;
 }

#fixed {
    position: static;
    width: 100%;
    border: 3px solid #f00;
}
#nonfixed {
    margin-top: 50px;
    border: 3px solid #00f;
}     

Note that position:static, this gives the expected result (fiddle):

enter image description here

However, change position:static to fixed, and you get this (fiddle)

enter image description here

Even though the #fixed div is not inside #nonfixed, it has taken on the top margin of #nonfixed. This happens in both Chrome and Firefox. Curiously, the dev tools in both browsers do not show the #fixed div having any margins, so clearly it's being positioned as if it was fixed inside the #nonfixed div.

If I add top:0 to the #fixed ruleset the div goes back to the top of the window, but shouldn't this appear at the top (i.e. where it would in normal flow, but without affecting other elements) in the absence of a top specification?

For completeness: position:relative produces the same result as static and absolute looks the same as fixed.

I cannot find anything in the spec that directly addresses why an absolutely positioned element should be positioned relative to a subsequent sibling. In fact, reading the spec I find (emphasis mine):

10.6.4 Absolutely positioned, non-replaced elements

...

If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and apply rule number three below.

...

  1. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content per 10.6.7, set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'

This seems to indicate the #fixed box should indeed be at the top of the viewport.

Since both FF and Chrome do the same thing I'm guessing it's supposed to work this way, but I'd like to know why. Can anyone explain this behavior in terms of the spec?

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • 2
    Dupe of http://stackoverflow.com/questions/24560958/how-does-margin-of-separate-element-affect-position-of-fixed-element? – j08691 Dec 03 '15 at 23:26

1 Answers1

2

You'll notice that the "fixed" div is actually at the top of the body, the position and size of which match those of the "nonfixed" div.

This is most certainly due to the top margins of the body and div#nonfixed collapsing. See http://www.w3.org/TR/CSS21/box.html#collapsing-margins

8.3.1 Collapsing margins

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

(...)

Two margins are adjoining if and only if:

  • both belong to in-flow block-level boxes that participate in the same block formatting context
  • no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
  • both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
    • top margin of a box and top margin of its first in-flow
    • (...)

The topis relative to the containing block, which is apparently not bodybut html (the root element).

jcaron
  • 17,302
  • 6
  • 32
  • 46
  • 1
    So if I understand correctly: 1) The `fixed` div is taken out of flow; 2) The top margin of `nonfixed` is then collapsed with the margin of its containing box (`html` or `body`); and, critically, 3) the collapsed margin (`max(0,50)`) is defined to be an attribute of the _containing block_, not `nonfixed`. This causes `fixed` to be laid out according to the new top margin. This is really counter-intuitive. But then I also believe the CSS layout model is irretrievably flawed since it cannot express a number of common layout scenarios without Javascript assistance. – Jim Garrison Dec 03 '15 at 23:43
  • This is a reasonable answer and contributes to understanding the issues... downvoter care to comment? – Jim Garrison Dec 03 '15 at 23:45
  • From the "collapsing margins" section of the spec: _"If the element's margins are collapsed with its parent's top margin, the top border edge of the box is defined to be the same as the parent's."_ I can't interpret this to say the parent's margin gets the collapsed value. – Jim Garrison Dec 04 '15 at 00:10
  • Well, if the top edges are the same, but there's still a margin, it needs to be somewhere. The margin still belongs to the child element, but it affects the layout of the parent. – jcaron Dec 04 '15 at 00:14
  • That's just weird and totally counter-intuitive. I have a typesetting background (from the '80s) and know page layout is a hard problem, but CSS seems to be particularly quirky and full of "unintended consequences". – Jim Garrison Dec 04 '15 at 21:30