I have a bunch of CSS that is applied to a parent element and its children:
.parent {
position: fixed;
top: 0px;
}
.el {
position: fixed;
top: 5px;
z-index: 100;
}
.bodycontent {
z-index: 1;
position: relative;
}
<div class="parent">
<div class="el">
<button></button>
</div>
</div>
<div class="bodycontent"></div>
The page is made so that when it is scrolled, .parent
goes underneath .bodycontent
but .el
goes above it. This works how I want it to in Firefox but not on Chrome.
Any suggestions? I have tried messing around with different z-index
values and different position
values with no success.
From version 22 onwards, this is the way Chrome intentionally handles the stacking of fixed
elements. As stated in an article by Google themselves:
In Chrome 22 the layout behavior of
position:fixed
elements is slightly different than previous versions. Allposition:fixed
elements now form new stacking contexts. This will change the stacking order of some pages, which has the potential to break page layouts.
(https://developers.google.com/web/updates/2012/09/Stacking-Changes-Coming-to-position-fixed-elements?hl=en)
Firefox is working as it intends too. The Mozilla docs state that this behaviour is localised to mobile WebKit and Chrome 22 onwards:
on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is "auto"
(https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context)
The result of this change means that Chrome will always create a new stacking context even if the z-index
of the parent container is set to auto
(the default). This differs from position: absolute;
and position: relative;
as they only form their own stacking context when z-index
is not set to auto
.
Most elements on a page are in a single, root stacking context, but absolutely or relatively positioned elements with non-auto
z-index
values form their own stacking contexts (that is, all of their children will be z-ordered within the parent and not be interleaved with content from outside the parent). As of Chrome 22,position:fixed
elements will also create their own stacking contexts.
(https://developers.google.com/web/updates/2012/09/Stacking-Changes-Coming-to-position-fixed-elements?hl=en)
The effect of this means that in your example .el
's z-index
is computed relatively to its parent, .parent
. It is displayed under .bodycontent
because:
.bodycontent
's z-index
is relative to the root.el
's z-index
is relative to .parent
.parent
's z-index
is relative to the root.parent
's z-index
is not specified so it is set to the default auto
(in effect, 0
).parent
has a lower z-index
than .bodycontent
and is therefore displayed under it. Because .el
belongs to it, it too is displayed under .bodycontent
.body {
margin: 0;
}
div {
height: 100px;
width: 100px;
}
.parent {
background-color: red;
position: fixed;
top: 0;
}
.el {
background-color: blue;
left: 25px;
position: fixed;
top: 25px;
z-index: 100;
}
.bodycontent {
background-color: green;
left: 50px;
position: relative;
top: 50px;
z-index: 1;
}
<div class="parent">
<div class="el"></div>
</div>
<div class="bodycontent"></div>
The above code will produce the following results in Chrome and Firefox:
It would appear that Chrome is not following the W3C spec and that this change was made so that the desktop implementation matched the mobile implementation:
Mobile browsers (Mobile Safari, Android browser, Qt-based browsers) put position:fixed elements in their own stacking contexts and have for some time (since iOS5, Android Gingerbread, etc) because it allows for certain scrolling optimizations, making web pages much more responsive to touch. The change is being brought to desktop for three reasons:
1 - Having different rendering behavior on “mobile” and “desktop” browsers is a stumbling block for web authors; CSS should work the same everywhere when possible.
2 - With tablets it isn’t clear which of the “mobile” or “desktop” stacking context creation algorithms is more appropriate.
3 - Bringing the scrolling performance optimizations from mobile to desktop is good for both users and authors.
Firefox is handling the stacking in the correct way.
The only way this behaviour can be circumvented is to move .el
out of .parent
and instead make it a sibling:
body {
margin: 0;
}
div {
height: 100px;
width: 100px;
}
.parent {
background-color: red;
position: fixed;
top: 0;
}
.el {
background-color: blue;
left: 25px;
position: fixed;
top: 25px;
z-index: 100;
}
.bodycontent {
background-color: green;
left: 50px;
position: relative;
top: 50px;
z-index: 1;
}
<div class="parent"></div>
<div class="el"></div>
<div class="bodycontent"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With