I don't think this is a bug with jQuery - does it seem to be due to a legitimate dependency between the H1 field and the body element?
Yes: body fields and h1 collapsing , so not only the default h1 offset is edge, but also the body. This is why you were able to make these observations:
- Setting the body boundary solves the problem - it seems strange, but compatible in browsers? (not a viable solution)
- Removing H1 fields solves the problem (not a viable solution)
In any case, setting the body to position: relative , you say #overlay to fully position yourself with a higher body offset as the source. Then your script moves it relative to the offset #existing . The value of its offsetTop refers to the viewport, which is calculated based on the position of this block ... which in itself refers to h1, since it immediately follows h1 in the normal stream.
Since the fields h1 and body elements are reset, they have the same rendering fields. Then the double thing happens:
#existing compresses h1 as the next sibling in the normal stream. This increases the offset from the viewport (in your CodePen test case, at the top of the preview area), resulting in a larger offsetTop .
When the body is set to position: relative , #overlay ends up being positioned with its beginning set according to its beginning, which was also pushed out due to merging with the h1 brand. This increases the top offset of its beginning, which would not have happened if you hadn't positioned the body, because then #overlay instead uses a viewport source that never moves.
The distance #existing from the top of the viewport is added to the offset #overlay from its beginning, which is the body, which leads to this effect.
In short: due to the collapse of the margin, the browser ends up taking into account the downward shifts in both h1 and the body. H1 affects #existing and, in turn, its offsetTop , and the body affects #overlay when you #overlay it relatively. Thus, the shear effect appears twice.
As a quick workaround, you can subtract the h1 limits from #existing offsets for #overlay :
$("#overlay").css({ left: $("#existing").offset().left - $("h1").offset().left, top: $("#existing").offset().top - $("h1").offset().top })
Updated example
Note that using $(document.body) instead of $("h1") above will not work. This is because crash crash is a purely rendering effect and does not actually affect the body displacements until you give it your own margin (in other words, the body fields are still calculated to zero, so the DOM is no wiser).
Not directly related to the problem, but worth mentioning:
- Fields from H1 seem to change where the body 0,0 is calculated, even if the background on the body extends to the edge, and its offsetTop reports the properties 0
The first and last parts of this paragraph were discussed above.
As for the background of the body: as long as it seems to extend to the edge, this expanded background does not actually belong to the body - it spreads from the body to and, therefore, belongs to the root element (html) in the viewport. See this answer for an explanation.
Oh and this:
This is not a mistake, because the behavior is consistent between FF, Chrome, IE9 and Safari on Win7.
Made me smile. Because this time someone is right in saying this.