I need to give an element position fixed, but I can't position it relatively to the viewport, I need it to be positioned relatively to a container.
I managed to do so, but I wonder how and why it works, because actually I think position fixed is ALWAYS positioned relatively to the viewport and NOT to parent elements.
Here my (working) code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
height: 2000px;
}
.container {
position: relative;
}
.sidebar {
width: 200px;
background-color: red;
height: 200px;
position: absolute;
left: 100px;
top: 100px;
}
.fixed {
width: 100px;
height: 100px;
background-color: green;
position: fixed;
/* top: 0;
left: 0; */
margin-left: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar">
<div class="fixed"></div>
</div>
</div>
</body>
</html>
Fiddle: https://jsfiddle.net/tnwLycao/
Element "fixed" can easily be positioned with margins (e.g. margin-left/margin-top). However, when I deactivate the margins and try to position "fixed" with top/left it positions itself relatively to the viewport again, not relatively to the parent container/element.
Can someone give me a hint how and why this works?
An element with position: fixed
is indeed positioned relative to the viewport (or browser). However, because it is an absolutely positioned element, it is "positioned relative to the initial containing block established by the viewport".
This is laid out in the position
documentation:
An absolutely positioned element is an element whose computed
position
value isabsolute
orfixed
. Thetop
,right
,bottom
, andleft
properties specify offsets from the edges of the element's containing block. (The containing block is the ancestor relative to which the element is positioned.) If the element has margins, they are added to the offset.
That is to say, when you specify margin-top
and margin-left
, these values are relative to the parent. And because the element is positioned relative to the parent, the default top
and left
are inherited from the parent. In your example, the .fixed
element has a top
value of 100px
because it inherits the top
value of 100px
from .sidebar
(the parent). When you set top: 0
on .fixed
, you are overriding this value (going from top: 108px
to top: 0
):
Because of this, the element appears to be taken 'out of flow'. However, it is still always positioned relative to the viewport; it just had an initial offset (which it inherited from its parent).