【问题标题】:Video and z-index inside scaled element: some divs disappear缩放元素内的视频和 z-index:一些 div 消失
【发布时间】:2018-09-14 03:52:10
【问题描述】:

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

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

示例

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

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

结论

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

如果我满足以下条件,则问题不存在:

  • 用 div 替换 video 标签
  • position: absolute;从兄弟姐妹中删除到.on-top(即.below
  • .content 中删除overflow: hidden;
  • 如果我移动.on-top,使其位于文档流中的视频标签之后

(当然,由于项目的具体原因,这些变通方法实际上都不适合我。我也不能给视频元素一个负的 z-index,我需要使用overflow: hidden;。 )

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

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

浏览器

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


更新 1

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

更新 2

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

更新 3

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

【问题讨论】:

  • 显然scale 弄乱了 Safari 和 Chrome 中的 z-index 信息。检查这个:stackoverflow.com/questions/35681829/… 有一些解决方法,但似乎你已经想通了!
  • 谢谢何塞!我已经尝试了解决方法,但它们并没有帮助我。我必须在某些时候使用overflow: hidden;,这对我来说似乎是个问题(当与position: relative;position: absolute; 结合使用时。
  • 看起来这是一个 webkit/blink (safari/chrome/opera) 问题!我在 Firefox、Edge 和 IE11 上没有遇到这个问题
  • @Baksteen 我也一样。我只能在 Chrome 和 Safari 中重现它。

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


【解决方案1】:

这看起来像是 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>

【讨论】:

  • 感谢您指出这一点 :) 我创建了一个包含新见解的更新演示:jsfiddle.net/iafiawik/bpos8nw3 我添加了一个未缩放的外部元素,但随着内部元素的缩放,它会获得更新的宽度和高度值上和下。我会试一试,看看它在实际项目中是如何工作的。
  • @iafiawik 查看修改后的答案。
  • 感谢您的详细解答,非常感谢。我想避免不得不操纵单个元素以防止它们消失。据我所知,使您的解决方案有效的原因是您将 200px border-left 添加到 .on-top。如果视频上方的元素数量有限,这可能是一个足够好的解决方案,但对我来说并非如此。我的 HTML 是可视化编辑器的输出,所以我不知道要呈现元素时会有哪些元素。
  • 你好,我在我的解决方案中使用了你的答案(它作为答案发布)。感谢您的帮助:)
【解决方案2】:

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

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

编码愉快!

【讨论】:

  • 这对于那些元素数量很少/受控的人来说绝对是一个选择。对我来说可悲的是,我的 HTML 是可视化编辑器的输出,所以我不知道要呈现文档时会有哪些元素。我当然可以将translateZ 添加到所有元素(通过某个类),但我发现这比我目前的解决方法更有效。无论如何,谢谢:)!
  • 啊,好吧,没有意识到这是您的用例。对于全局修复,只需使用 * {  -webkit-transform: translateZ(0); }。这会将规则应用于所有内容。除了纠正显示错误之外,它不应该对您的布局产生任何影响。
  • 操作繁重吗?
  • 如果你知道什么类型的元素会在那个位置,最好把它们具体列出来,即h1, h2, div { },但如果在适当的情况下谨慎使用,*很好用,不会浪费你的加载时间或任何东西。
  • 谢谢,我会试一试 :) 我还更新了一些关于我的 HTML 结构的问题。
【解决方案3】:

在花了很多时间研究这个问题并尝试了很多不同的方法之后,我得出的结论是,没有解决方案可以解决我的问题。如果您能够控制消失的元素的 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>

【讨论】:

  • 在下面查看我的答案。这是我多年来在开发基于浏览器的游戏时遇到的 webkit 渲染中的一个奇怪故障,应该可以通过一行来修复它。很抱歉在您将所有精力投入解决方法之前没有抓住问题
【解决方案4】:

如果您可以稍微修改一下 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/

【讨论】:

  • 您好,感谢您的回答!对于那些具有简单 HTML 结构的人来说,这实际上可能是一种解决方法。 :) 对我来说不幸的是,我的 HTML 是可视化编辑器的输出,所以我不知道要呈现页面时会有哪些元素。这也意味着我不能将每个单独的元素设置为width: 100%; height: 100%;,因为这会弄乱指针事件等。
【解决方案5】:

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

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

【讨论】:

  • 嗨!感谢您的输入。我并不是要听起来忘恩负义,但问题已经提到删除overflow: hidden 会使问题消失。所以overflow: hidden 显然是有原因的。关于另一个建议,如果您可以提供一个具有与overflow: hidden 相同功能的“节点之间”的工作示例,消除错误行为但保持其他所有内容相同,那就太好了。
  • Arf 是的,对不起。我错过了这个。我冲进了jsfiddle
  • @Sandwell 没问题,谢谢!你有额外节点的工作示例吗?
  • @iafiawik 我试过了,但效果不佳。你可以考虑像我更新的 jsfiddle 一样在视频标签上使用负 z-index 吗?
  • @Sandwell 我意识到这是为数不多的看似相当简单的解决方法之一,但是......我有时会在视频后面放置其他元素,并在视频上放置负 z-index给我带来了一堆新问题。
【解决方案6】:

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

【讨论】:

  • 我同意,这是最好的答案。不幸的是,此时重写为position: relative; 不是一种选择——这会花费太多时间。
【解决方案7】:

上周我偶然发现了与此类似的东西,其中包括定位绝对元素和变换...

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

CSS transform: translate moves postion:fixed inner Div

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

肯定是超级奇怪的行为,但该链接提供了更多链接以帮助使事情更加清晰 - 就像它的行为符合规范一样。

【讨论】:

  • 感谢您的回复!你有没有看到你是否可以让这个技巧与问题中链接的 JSFiddle 演示(再现行为的最小示例)一起使用?对我来说,如何将这种方法应用于演示的细节并不明显。
  • 您好!感谢您的输入。我不知道如何将其应用于我的示例 (jsfiddle.net/iafiawik/Lcox1ecc)。我的问题是z-index,而不是定位,但也许它们有某种关联?如果有,怎么做?
【解决方案8】:

这是因为溢出被​​隐藏了。这里是工作链接

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

.content {
overflow:visible;
}

【讨论】:

  • 是的,我知道(此信息包含在我的问题中)。我需要让它与overflow: hidden; 一起工作。你有什么想法可以让它发挥作用吗?
【解决方案9】:

可能会迟到,但只是发布以防有人发现它有帮助。 在带有变换动画的父容器元素下添加一个空 div,任何东西都不会消失。动画不做任何事情,但它强制浏览器使用硬件加速渲染所有元素。

&lt;div class="emptydiv"&gt;&lt;/div&gt;

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 1970-01-01
  • 2013-10-29
  • 1970-01-01
相关资源
最近更新 更多