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

时间:2018-04-04 14:19:33

标签: javascript css google-chrome z-index scaletransform

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

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

示例

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

链接到exmaple:https://jsfiddle.net/iafiawik/Lcox1ecc/

enter image description here

结论

  • 看起来元素的大小很重要。我做得越大,它消失之前的比例值就越大。
  • 我还测试了在元素上直接用CSS设置transform: scale(1.4),行为是一样的。

如果我:

,则问题不存在
  • 将视频代码替换为div
  • 将兄弟姐妹中的position: absolute;移至.on-top(即.below
  • overflow: hidden;
  • 移除.content
  • 如果我移动.on-top,那么它会放在文档流程中的视频标记之后

(但当然,由于项目的具体原因,这些变通方法在现实中都不适合我。我也不能给视频元素一个负z-index而我需要来使用{{1} }。)

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

  • 为视频代码添加负z-index(不能这样做,因为我有时会在视频后面放置元素)
  • 删除overflow: hidden;(我无法移除overflow: hidden;

浏览器

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

更新1

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

更新2

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

更新3

有很多答案可以修改视频overflow: hidden;z-index添加到translateZ元素。演示已经表明这两种方法都可以解决这个问题。 但是,由于我的HTML结构是可视化HTML编辑器的输出(长篇故事......),我不知道它们将是什么元素,或者它们应该位于视频的前面,下面还是旁边。因此,我正在寻找一种解决方案,不需要更改缩放元素内的单个元素。

9 个答案:

答案 0 :(得分:8)

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

Chrome Scale

在Firefox中的位置:

Firefox Scale

现在,显然,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>

答案 1 :(得分:4)

在这里:https://jsfiddle.net/Lcox1ecc/423/

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

快乐的编码!

答案 2 :(得分:3)

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

This bug report几乎涵盖了我的问题,但它没有为它提供修复。

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

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

enter image description here

...但不是scale(1.228)

enter image description here

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

enter image description here

这不是一个完美的解决方案,因为人们可能会遇到缩放元素和最外层包裹元素之间的小差距(舍入问题),但考虑到这种情况,这是我能做的最好的。

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>

答案 3 :(得分:2)

一种方法,如果你可以修改你的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/

答案 4 :(得分:1)

我将z-index:-1;放在video上,从而解决了这个问题。

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我偶然发现了与绝对元素和变换相关的类似内容......

我不知道如果这会帮助你,但这里有一个链接。

CSS transform: translate moves postion:fixed inner Div

最后我通过使用转换来修复它:translateX(none)vs translateX(0)。

确实存在超级奇怪的行为,但该链接提供了一些更多链接,以帮助使事情更加清晰 - 就像每个规范的行为一样。

答案 7 :(得分:0)

因为溢出被​​隐藏而发生。这是工作链接

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

.content {
overflow:visible;
}

答案 8 :(得分:0)

可能已经晚了,但是只是发布以防有人觉得有用。 在带有转换动画的父容器元素下添加一个空的div,并且什么也不会消失。该动画不执行任何操作,但会强制浏览器使用硬件加速来渲染所有元素。

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

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