Positioning a fixed element inside another fixed element is behaving differently in Chrome / Safari vs Firefox.
将固定元素定位在另一个固定元素中的行为在Chrome / Safari和Firefox中表现不同。
This answer explains well the expected behavior for a fixed div inside a relative one, and MDN is pretty clear on this:
这个答案很好地解释了相对一个内部固定div的预期行为,MDN对此很清楚:
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.
我不明白的是Firefox正在使用固定div中的固定div做什么。我期望的是,子元素在悬停时与包装器一起移动。
.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;
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!
-
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!
-
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!
-
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!
-
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!
Any thoughts? I'm looking for a workaround to have consistency across browsers, too.
有什么想法吗?我正在寻找一种解决方法,以便在浏览器之间实现一致性。
Add this to glitch it even more on FF :
添加这个以便在FF上出现更多故障:
.header:hover{
height:200px;
}
On hover, it triggers a repaint, then FF recalculate the position of the element.
在悬停时,它会触发重绘,然后FF重新计算元素的位置。
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
使用FF 46.0.1,Chrome 54.0.2840.71和Safari版本9.1.1(11601.6.17)进行测试。注意:我已经读过这个问题
5
11/18/16 Update - The CSSWG got back to me and said that it should create a new stacking context:
11/18/16更新 - CSSWG回复我并说它应该创建一个新的堆叠上下文:
You're right, this was supposed to be merged into the positioning spec as well - reflected now. Thanks.
你是对的,这也应该被合并到定位规范中 - 现在反映出来。谢谢。
新的CSS位置规范差异
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:
固定位置元素应始终相对于视口放置,特别是位置:固定元素的包含块是由10.1.3中的“视口”建立的:
If the element has 'position: fixed', the containing block is established by the viewport [...]
如果元素具有'position:fixed',则包含块由视口[...]建立
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),
9.3.1还说明了这一点,对于普通的非分页媒体(像这样),
[...] 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.
[...]对于手持,投影,屏幕,tty和tv媒体类型,该框相对于视口是固定的,滚动时不会移动。
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.
您的代码中发生的是您在悬停时更改父元素的left属性的值,并且您也希望子元素也可以移动。但是,子元素(正确)不移动。
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').
[If]'left'和'right'是'auto'且'width'不是'auto',[...]将'left'设置为静态位置,否则将'right'设置为静态位置。然后解决'左'(如果'方向是'rtl')或'右'(如果'方向'是'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
.
我相信,这解释了为什么子位置:固定元素最初设置为左:-200px;如果它是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.
在这种情况下,Chrome和Safari似乎正在做一些不同于规范建议的事情;它们要么导致完全重新流动,要么它们设置了位置:固定元素以从祖先继承左侧属性。根据Oriol下面链接的CSS工作组草案,如果你愿意,这似乎是在董事会之上。但是,在规范更新之前,它仍然是非标准行为。
长话短说,Chrome和Safari目前都是错误的,但最终一旦规范更新,它们就会正确,Firefox将不得不更新其渲染行为。
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
:
让.header div继承你的新左侧属性,因为Chrome就是这样做的,这就是你寻求的行为。我也调整了.header的宽度,所以它不会覆盖.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;
}
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!
-
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!
-
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!
-
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!
-
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!
-2
So, I think problem has arisen due to the bug in implementation of left
in Firefox.
所以,我认为由于Firefox中实现左边的错误而出现了问题。
When hovering When hovering .wrapper
, .header
should get new left
value from its parent .wrapper
i.e. 0px
..wrapper
, the left position of .header
should be calculated using the left
value from its parent .wrapper
as no explicit left
value is given to .header
.
当悬停.wrapper时,.header应该从其父.wrapper获得新的左值,即0px。当悬停.wrapper时,.header的左侧位置应使用其父.wrapper中的左值计算,因为没有给.header明确的左值。
I think its due to bug in Firefox. If you activate :hover
pseudo class of .wrapper
using Firebug or the default developer tool, the left position of .header
is maintained like in Chrome (but in sudden manner).
我认为这是由于Firefox中的错误。如果你使用Firebug或默认的开发人员工具激活:.wrapper的hover伪类,.header的左侧位置就像在Chrome中一样(但是以突然的方式)。
Tested on Firefox 49.0.2 and Chrome 54.0.2840.71
在Firefox 49.0.2和Chrome 54.0.2840.71上测试过