堆叠位置的上下文:固定的伪元素

时间:2015-08-18 21:59:56

标签: css cross-browser background-image css-position z-index

我正在尝试通过this post from Four Kitchens中描述的代码实现固定背景图像,但是使用多个背景图像而不是一个。这是帖子的代码:

.what-we-do-cards {
  @include clearfix;
  border-top: 10px solid rgba(255, 255, 255, .46);
  color: $white;
  padding-bottom: 4em;
  overflow: hidden; // added for pseudo-element
  position: relative; // added for pseudo-element

  // Fixed-position background image
  &::before {
    content: ' ';
    position: fixed; // instead of background-attachment
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background-color: white;
    background: url('/img/front/strategy.jpg') no-repeat center center;
    background-size: cover;
    will-change: transform; // creates a new paint layer
    z-index: -1;
  }
}

基本思路是使用:before伪元素为固定位置背景图像创建内容部分,但在帖子中链接的示例仅使用单个固定位置部分。

我的解决方案jsfiddle适用于Safari和Chrome,但不适用于Firefox,而我正试图弄清楚浏览器如何以不同方式处理伪元素。另外,如果您在Chrome中注释will-change: transform;(第25行),您会看到与Firefox相同的行为,我认为这归因于Chrome triggering a stacking context。我不确定为什么Safari没有在Chrome中触发堆叠上下文。

关于堆叠上下文here有一个很好的答案,但我不确定它如何与固定位置元素,伪元素和显式设置z-index一起使用。

编辑:原始的jsfiddle展示了如何在浏览器中创建(或不创建)固定元素的包含框,但没有真正显示背景图像如何变化。 @Oriol解释了如何添加transform: rotate(0);强制在Firefox上创建包含框,但它也删除了Chrome中固定的视图关系效果。我创建了一个new jsfiddle - 导致渲染差异的原因是什么?

1 个答案:

答案 0 :(得分:1)

will-change: transform确实产生了堆叠上下文。但是,堆叠上下文与此问题无关。事实上,CSS工作组最近resolved position: fixed已经创建了堆叠上下文。

相反,这是由于为固定位置元素创建了一个包含块。

根据The will-change property

  

如果属性的任何非初始值将导致该元素   为固定位置元素生成一个包含块,指定   will-change中的该属性必须导致该元素生成   用于固定位置元素的包含块。

因此,will-change: transform会为固定位置元素生成一个包含块,因为根据The Transform Rendering Model

  

转换的none以外的任何值都会导致创建   堆叠上下文和包含块的内容。该对象充当   一个包含固定位置后代的块。

我认为Safari不需要will-change: transform因为它认为固定元素应该为固定后代创建一个包含块,即使这不是标准的。这并不奇怪,因为在CSSWG解决之前,固定元素在Webkit浏览器上产生了堆叠上下文。

Firefox支持will-change,但尚未实现此行为。但是,您可以通过将transform设置为除none以外的任何内容来实现相同的结果,例如

.fixed { transform: rotate(0); }

body { margin: 0; }
.fixed {
  height: 20vh;
  transform: rotate(0); /* Containing block for fixed elements */
}
.fixed:before {
  content: '';
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
.one:before { background: orange; }
.two:before { background: blue; }
.three:before { background: black; }
.four:before { background: gray; }
.five:before { background: purple; }
<div class="container">
  <div class="one fixed"></div>
  <div class="two fixed"></div>
  <div class="three fixed"></div>
  <div class="four fixed"></div>
  <div class="five fixed"></div>
</div>