缩放元素内的视频和 z-index:一些 div 消失

Video and z-index inside scaled element: some divs disappear

我在 Chrome 和 Safari 中有一些奇怪的行为。我有一个缩放 (transform: scale()) 容器,其中包含视频和其他元素。在某些缩放比例下,具有高 z-index 的绝对定位元素消失并且不会再次出现。

我该如何解决这个问题? 请注意,我不能为视频元素提供负 z-index,我需要使用 overflow: hidden;.

例子

我做了一个上下缩放最外层容器的例子。在特定比例值下,带有 class .on-top(和文本 "I should always be on top.")的元素消失。再次缩小时突然出现

Link 例如:https://jsfiddle.net/iafiawik/Lcox1ecc/

结论

问题不存在如果我:

(但当然 none 由于项目特定原因,这些解决方法在现实中对我有用。我也不能为视频元素提供负 z-index,我 需要 使用 overflow: hidden;.)

社区建议的解决方法(谢谢!)

浏览器

我在 Chrome (Mac) 和 Safari (Mac) 中看到过这个问题。


更新 1

似乎 this bug report 几乎涵盖了我的问题。但是,它没有提供修复方法。

更新 2

我已经通过提供我对这个问题的解决方案来回答我自己的问题。

更新 3

有很多答案进来,要么修改视频的z-index ,要么 添加 translateZ.on-top 元素.演示表明,这两种方法都可以解决问题。 但是,由于我的 HTML 结构是可视化 HTML 编辑器的输出(长话短说......),我不知道那里会有什么元素,或者它们应该在前面、下面还是下一个到视频。因此,我正在寻找一种不需要更改缩放元素内的 individual 元素的解决方案。

上周我偶然发现了与此类似的定位绝对元素和转换...

我不知道这是否对您有所帮助,但这是 link。

CSS transform: translate moves postion:fixed inner Div

最后我使用转换修复了它:translateX(none) vs translateX(0).

确实是超级奇怪的行为,但是 link 提供了更多 link 来帮助使事情变得更加清晰 - 就像它的行为符合规范一样。

我通过将 z-index:-1; 放在 video 上来解决这个问题。

https://jsfiddle.net/Lcox1ecc/312/

发生溢出是因为 hidden.Here 正在工作 link

https://jsfiddle.net/Lcox1ecc/322/

.content {
overflow:visible;
}

它看起来像是 Chrome 中的错误。请注意,当您缩放图像时,元素检查器会不断告诉您 #scaled 的大小为 1024x768:

在 Firefox 中:

现在,显然,Chrome 使用错误的大小得出结论 .on-top 完全.content 并由于隐藏溢出而将其隐藏(它不应该这样做,但显然它正在尝试优化显示在视频上方的任何元素)。示例:

Scale: 1.225
Parent width: 1254.40
Child left: 1254.40 - (100 + 90) * 1.225 = 1021.65
Result: less than 1024 (partially inside)

Scale: 1.230
Parent width: 1259.52
Child left: 1259.52 - (100 + 90) * 1.230 = 1025.82
Result: greater than 1024 (completely outside)

不幸的是我找不到一个优雅的解决方案。理想情况下,您应该修改 HTML 标记和 CSS,也许将顶部元素与左边缘对齐。作为最后的手段,您可以使用透明边框将元素向左移动更多:

var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaleInfo = document.getElementById("scale-info");

function step() {
  container.style.transform = "scale(" + (currentScale / 100) + ")";
  scaleInfo.innerText = "Scale: " + (currentScale / 100);
  if (currentScale === goalScale) {
    shouldScaleUp = false;
  }
  if (currentScale === startScale) {
    shouldScaleUp = true;
  }
  if (shouldScaleUp) {
    currentScale += 0.5;
  } else {
    currentScale -= 0.5;
  }
  window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
.scale-info {
  position: fixed;
  left: 0;
  top: 0;
}

#scaled {
  background: #cccccc;
  width: 1024px;
  height: 768px;
  position: fixed;
  left: 200px;
  top: 200px;
}

.content {
  height: 100%;
  overflow: hidden;
  position: relative;
  margin-left: auto;
  margin-right: auto;
  background: rgba(34, 34, 56, 0.2);
}

.below {
  position: absolute;
  width: 300px;
  height: 300px;
  right: 0px;
  top: 100px;
  background: purple;
  z-index: 1;
  opacity: 0.8;
}

.below-2 {
  z-index: 3;
  right: 100px;
}

.below-3 {
  z-index: 4;
  right: 400px;
}

.on-top {
  position: absolute;
  width: 50px;
  right: 100px;
  top: 150px;
  background: pink;
  z-index: 5;
  padding: 20px;
  /* a 200px border moves the element towards left */
  border-left: 200px solid transparent;
  background-clip: padding-box;
}

.on-top h1 {
  font-size: 20px;
}

#video {
  position: absolute;
  z-index: 4;
  width: 1024px;
  height: 768px;
  background: rgba(0, 0, 0, 0.4);
}
<div id="scale-info"></div>

<div id="scaled">
  <div class="content">
    <h2 class="below below-1"> I have z-index 1</h2>
    <div class="on-top">
      <h1> I should always be on top.<br> I have z-index 5</h1>
    </div>
    <h2 class="below below-2"> I have z-index 3</h2> <video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
    <h2 class="below below-3"> I have z-index 4</h2>
  </div>
</div>

我非常喜欢 Salman A 的回答。 唯一想到的就是用 position: relative 重写。 但我不知道这是否是一个选项。

一种方法,如果您可以稍微修改一下 html,就是将有问题的元素包装在一个与视频和容器大小相同的容器中,并使用适当的 z-index。这样你就会有相同大小和位置的清晰层,你可以在其中放置更复杂的元素。例如:

   <div id="top-container">
     <div class="on-top">
      <h1>
        I should always be on top.<br /> I have z-index 5
      </h1>
    </div>
   </div>

  #top-container {
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: 5;
  }

https://jsfiddle.net/06oykj8o/4/

在花了很多时间研究这个问题并尝试了很多不同的方法之后,我得出的结论是没有解决方案可以解决我的问题。如果您能够控制消失的元素的 z 索引,则有一些解决方案可以解决此问题,但我无法这样做,因为 HTML 的结构未知(它是输出HTML 编辑器)。我一直在寻找一种解决方案,不需要将单个子项更改为按比例缩放的父项,但到目前为止我还没有找到任何解决方案。

This bug report 几乎涵盖了我的问题,但没有提供解决方案。

我可以确认发生这种情况是因为元素在缩放容器的原始宽度和高度之外:

该元素在 scale(1.227) 处可见(红色边框表示 #scaled 的原始大小):

...但不在 scale(1.228):

因此,我的解决方案是在未缩放的缩放元素之外添加另一个环绕元素,但根据其第一个子缩放值更新其 widthheight 属性。此元素具有 overflow: hidden; 并阻止元素可见。

这不是一个完美的解决方案,因为缩放元素和最外层环绕元素之间可能会出现小间隙(舍入问题),但这是我在这种情况下所能做的最好的解决方案。

var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaledContainer = document.getElementById("resized-container");
var scaleInfo = document.getElementById("scale-info");

function step() {
  var contentWidth = 1024;
  var contentHeight = 768;
  container.style.transform = "scale(" + (currentScale / 100) + ")";

  scaledContainer.style.width = contentWidth * ((currentScale / 100)) + "px";
  scaledContainer.style.height = contentHeight * ((currentScale / 100)) + "px";

  scaleInfo.innerText = "Scale: " + (currentScale / 100);

  if (currentScale === goalScale) {
    shouldScaleUp = false;
  }
  if (currentScale === startScale) {
    shouldScaleUp = true;
  }

  if (shouldScaleUp) {
    currentScale += 0.5;
  } else {
    currentScale -= 0.5;
  }

  window.requestAnimationFrame(step);
}

window.requestAnimationFrame(step);
#resized-container {
  position: fixed;
  width: 1024px;
  height: 768px;
  overflow: hidden;
  border: 10px solid red;
  top: 200px;
  left: 200px;
}

#scaled {
  background: #cccccc;
  width: 1024px;
  height: 768px;
  position: absolute;
  transform-origin: left top;
}

.content {
  height: 100%;
  position: relative;
  margin-left: auto;
  margin-right: auto;
  background: rgba(34, 34, 56, 0.2);
}

.below {
  position: absolute;
  width: 300px;
  height: 300px;
  right: 0px;
  top: 100px;
  background: purple;
  z-index: 1;
  opacity: 0.8;
}

.below-2 {
  z-index: 3;
  right: 100px;
}

.below-3 {
  z-index: 4;
  right: 400px;
}

.on-top {
  position: absolute;
  width: 50px;
  right: -30px;
  top: 150px;
  background: pink;
  z-index: 5;
  padding: 20px;
}

.on-top h1 {
  font-size: 20px;
}

#video {
  position: absolute;
  z-index: 4;
  width: 1024px;
  height: 768px;
  background: rgba(0, 0, 0, 0.4);
}
<div id="resized-container">
  <div id="scaled">
    <div id="scale-info">

    </div>
    <div class="content">
      <h2 class="below below-1">
        I have z-index 1
      </h2>

      <div class="on-top">
        <h1>
          I should always be on top.<br /> I have z-index 5
        </h1>
      </div>

      <h2 class="below below-2">
        I have z-index 3
      </h2>
      <video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
      <h2 class="below below-3">
        I have z-index 4
      </h2>
    </div>
  </div>
</div>

给你:https://jsfiddle.net/Lcox1ecc/423/

您只需将 -webkit-transform: translateZ(0); 添加到 .on-top class。

编码愉快!

可能会迟到,但只是发帖以防有人觉得有用。 在带有变换动画的父容器元素下添加一个空的 div ,什么都不会再消失。动画不执行任何操作,但会强制浏览器使用硬件加速呈现所有元素。

<div class="emptydiv"></div>

    .emptydiv{
      transform:scale(1);
      animation:fix 3s infinite;
    }
    
    @keyframes fix{
      50%{
        transform:scale(1);
      }
    }