Positioning a fixed element inside another fixed element is behaving differently in Chrome / Safari vs Firefox.
This answer explains well the expected behavior for a fixed div inside a relative one, and MDN is pretty clear on this:
Fixed Positioning Do not leave space for the element. Instead, position it at a specified position relative to the screen's viewport and don't move it when scrolled. When printing, position it at that fixed position on every page.
What I don't understand is what Firefox is doing with a fixed div inside a fixed div. What I expect is that the child element moves along with the wrapper on hover.
.wrapper, .header {
position:fixed;
width:320px;
}
.wrapper:hover{
left:0px;
}
.wrapper{
width:320px;
height:100%;
background:white;
overflow:scroll;
left:-200px;
transition: all ease-out .3s;
}
ul {
margin-top:120px;
}
.header {
background:rgba(255,255,255,0.9);
}
body{
background:gray;
<div class="wrapper">
<div class="header">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vitae a, itaque commodi, odio et. Excepturi, obcaecati? Architecto repellendus omnis mollitia animi rem quasi at, odit aperiam voluptatibus voluptates earum!
</div>
<ul>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
</ul>
</div>
Any thoughts? I'm looking for a workaround to have consistency across browsers, too.
Add this to glitch it even more on FF :
.header:hover{
height:200px;
}
On hover, it triggers a repaint, then FF recalculate the position of the element.
Tests made with FF 46.0.1, Chrome 54.0.2840.71 and Safari Version 9.1.1 (11601.6.17). Note: I already read this question
11/18/16 Update - The CSSWG got back to me and said that it should create a new stacking context:
You're right, this was supposed to be merged into the positioning spec as well - reflected now. Thanks.
On the subject of which browser is correct:
fixed
position elements should always be placed relative to the viewport, specifically that the position: fixed
element's containing block is established "by the viewport" in 10.1.3:
If the element has 'position: fixed', the containing block is established by the viewport [...]
This containing block is formally called the "initial containing block".
9.3.1 also backs this up by saying that, for normal non-paged media (like this),
[...] In the case of handheld, projection, screen, tty, and tv media types, the box is fixed with respect to the viewport and does not move when scrolled.
What's happening in your code is that you are changing the value of the left
property of the parent element on hover, and you are expecting the child element to move, too. However, the child element is (properly) not moving.
10.3.7 says
For the purposes of calculating the static position, the containing block of fixed positioned elements is the initial containing block instead of the viewport.
(static position here meaning the position of the element if it were placed in the normal flow).
It also says:
[If] 'left' and 'right' are 'auto' and 'width' is not 'auto', [...] set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
This explains, I believe, why the child position: fixed
element is initially set to left: -200px;
per where it would be within its parent element if it were position: static
.
At this point, it looks like you believe the parent's new left
value should move the child element, I'm assuming, either because you expect the new left
property to be inherited by the child (which is not how left
works), or you expect it to re-flow the document, which doesn't happen on :hover
as I recall; the browser only re-paints on :hover
, which doesn't change the document flow, but does change the appearance of elements (e.g. background-color
, opacity
, visibility: hidden;
etc).
So... elements on re-paint shouldn't move unless there are pseudo-selectors that change the properties during temporary states (like :hover
), or transitions/animations at play.
In this situation, it appears that Chrome and Safari are doing something other than what the spec suggests; they are either causing a full re-flow, or they have set position: fixed
elements to inherit left
properties from ancestors. This appears to be above the board, if you will, according to the CSS Working Group draft linked by Oriol below. However, it's still non-standard behavior until the spec is updated.
Make the .header
div inherit your new left
property, since that's how Chrome is doing it and that is the behavior you seek. I also adjusted .header
's width just a bit, so that it won't cover the scroll bar on .wrapper
:
.wrapper, .header {
position: fixed;
}
.wrapper:hover {
left:0px;
}
.wrapper{
width:320px;
height:100%;
background:white;
overflow:scroll;
left:-200px;
transition: all ease-out .3s;
}
ul {
margin-top:120px;
}
.header {
background:rgba(255,255,255,0.9);
left: inherit;
width: 303px;
}
body{
background:gray;
}
<div class="wrapper">
<div class="header">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vitae a, itaque commodi, odio et. Excepturi, obcaecati? Architecto repellendus omnis mollitia animi rem quasi at, odit aperiam voluptatibus voluptates earum!
</div>
<ul>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
<li>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
</li>
</ul>
</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