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

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

我如何修复此问题? 请注意,我不能为视频元素提供负的z索引,我需要使用overflow: hidden;

示例

我已经制作了一个示例,用于上下缩放最外层的容器。在指定的刻度值时,类.on-top(和文本"I should always be on top.")的元素消失。当再次缩小时,它突然出现。

示例链接:https://jsfiddle.net/iafiawik/Lcox1ecc/

结论

  • 似乎元素的大小很重要。我将其设置得越大,它消失之前的比例值就越大。
  • 我还测试了直接在元素上使用css设置transform: scale(1.4),行为相同。

如果I:

则不存在问题
  • 将视频标签替换为div
  • 从同级删除position: absolute;.on-top(即.below)
  • .content中删除overflow: hidden;
  • 如果我移动.on-top,则将其放置在文档流中的视频标签之后

(当然,由于特定于项目的原因,这些变通方法在现实中对我都不起作用。我也不能为视频元素提供负的z索引,我需要才能使用overflow: hidden;。)

来自社区的建议解决办法(谢谢!)

  • 给视频标签一个负的z索引(不能这样做,因为我有时会在视频后面放置元素)
  • 删除overflow: hidden;(我无法删除overflow: hidden;)

浏览器

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


更新1

似乎this bug report几乎涵盖了我的问题。但是,它不提供对它的修复。

更新2

我已经通过提供此问题的解决方案回答了我自己的问题。

更新3

有很多答案要么修改视频的z-index,要么将translateZ添加到.on-top元素。演示表明,这两种方法确实解决了问题。 然而,由于我的HTML结构是可视的HTML编辑器的输出(长篇大论……),我不知道那里会有什么元素,或者它们应该在视频的前面、下面还是旁边。因此,我正在寻找一种不需要更改已缩放元素中的单个元素的解决方案。


解决方案

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

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

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

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

.但不是在scale(1.228)

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

这不是一个完美的解决方案,因为您可能会遇到缩放元素和最外面的包装元素之间的小差距(舍入问题),但在这种情况下这是我所能做的最好的。

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
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>

相关文章