CSS z-index 在 Webkit transform translate3d 后丢失

107
我有两个绝对定位的div元素,它们重叠在一起。两者都通过CSS设置了z-index值。我使用translate3d WebKit变换来使这些元素离开屏幕并再次进入屏幕。变换后,这些元素不再遵循其设置的z-index值。
请问有人能解释一下当我对它们进行WebKit变换时,div元素的z-index /堆栈顺序会发生什么事情吗?还能讲解一下我该如何保持div元素的堆栈顺序?
以下是我如何执行转换的更多信息:
在变换之前,每个元素都通过CSS设置这两个WebKit转换值(我使用jQuery来执行.css()函数调用):
element.css({ '-webkit-transition-duration': duration + 's' });
element.css({ '-webkit-transition-property': '-webkit-transform' });

然后使用translate3d -webkit-transform对该元素进行动画处理:

element.css({ '-webkit-transform': 'translate3d(' + hwDelta + 'px, 0, -1px)' });

顺便提一下,我尝试将translate3d的第三个参数设置为几个不同的值,以尝试在三维空间中复制堆栈顺序,但是没有成功。

此外,iPhone/iPad和Android浏览器是该代码需要运行的目标浏览器。两者都支持webkit转换。


你能发一个链接让我看一下例子吗? - Littlemad
1
我遇到了同样的问题。我有一个<iframe>标签,里面的元素样式为“-webkit-transform: translate3d(0,0,0)”以强制进行3D加速。结果发现,具有更高z-index的外部框架始终被内部iframe元素隐藏。只是视觉上隐藏,我可以“点击”不可见的外部元素。这只发生在移动Safari中。 - Morgan Cheng
我花了10个小时才弄清楚那是导致我的代码无法工作的原因。唉。 - Dikeneko
8个回答

58
这可能与以下有关:https://bugs.webkit.org/show_bug.cgi?id=61824 基本上,当您在z轴上应用3D变换时,z-index将不再起作用(您现在处于一个三维渲染平面中,请使用不同的z值)。如果您想要切换回子元素的2D渲染,请使用 transform-style: flat;

14
基本上,当你在 z 轴上应用 3D 变换时,z-index 就不能被考虑了(现在你处于一个三维渲染平面中,需要使用不同的 z 值)。如果你想要将子元素切换回 2D 渲染,则可以使用 transform-style: flat; - samy-delux
2
所以在“preserve-3d”模式下,我们必须使用变换的z轴来设置顺序,在平面模式下,我们应该使用z-index。问题是,在Safari上,与硬件加速的变换组合使用时,z-index会出现错误。 - Steven Lu
1
不起作用。只有在我通过类删除动画样式时才能正常工作。 - fdrv

46

这与samy-delux指出的bug密切相关。这只会影响那些被定位为absolute或relative的元素。为了解决此问题,您可以将以下CSS语句应用于每个以这种方式定位并引起问题的元素:

-webkit-transform: translate3d(0,0,0);

这将对元素应用变换,而不实际执行变换,但会影响其呈现顺序,使其在引起问题的元素上方。


使用Chrome(35.0.1916.114 m),我发现如果没有这个规则,在元素翻转后[transform: rotateY(180deg)],jQuery点击处理程序将不再为该元素工作。此外,在翻转之后,屏幕上会留下痕迹,特别是如果它们的不透明度改变了,除非translate3d存在!这篇文章有所帮助http://www.sitepoint.com/fix-chrome-animation-flash-bug/。 - Philip Murphy
2
这对我解决了一个非常棘手的问题,涉及到两个固定元素,其中一个包含一个3D变换元素。在应用上述修复之前,3D变换元素基本上会溢出并覆盖另一个元素。 - Collin James
1
只有在我删除类的动画样式时才能正常工作。 - fdrv

15
Bit Late to this but try putting on the elements that have lost their Z-index placing the following, I had an issue when doing some parallax stuff recently and this helped massively.
有点晚了,但尝试在失去Z-index放置以下元素,最近我在做一些视差效果时遇到了问题,这对我很有帮助。
transform-style: preserve-3d;
这可以节省时间。
transform: translate3d(0,0,0);

在其他需要GPU承受更大负荷的元素上


1
当你的元素是3D时,我不会期望变换会对GPU造成额外的负担。计算必须进行。你的观点基于什么? - Micros

7

等待查看示例

你尝试过使用transform scale(1)吗?我记得曾经遇到过类似的问题,我不得不重新排列元素的html顺序,并使用一个我不需要的transform,只是因为transform的z-index发生了变化。

如果我没错的话,每次使用transform时,它都会成为可用的最高z-index,并且按照html元素距离开始标记的最近元素进行排序。从上到下。

希望这能帮到你。


6
如果您使用-webkit-transform: translateZ(0px);样式设置可堆叠元素,z-index将对3D转换的div起作用。

在codepen上的片段 -> http://codepen.io/mrmoje/pen/yLIul

在此示例中,按钮stack upstack down将页脚的z-index(+/-1)相对于旋转元素(在本例中为img)升高和降低。


堆栈已经被点击,无法再次点击。 - clevertension
嘿 @Moje,我也在想这个问题。堆栈仍然无法再次点击。 - alchuang
为什么我没有想到在翻译元素中添加负z-index呢?谢谢。 - Will

3
我无法重现您在此处描述的问题。无论我做什么,z-index值都会在所有变换中得以保留。我正在使用Chromium(Google Chrome)进行测试。
translate3d函数的第三个参数操作元素的z轴。它的概念类似于z-index,但并不完全相同... z轴较低的元素位于值较高的元素下方。
我知道您尝试使用第三个参数的值来匹配所需的z-index,但问题是在CSS3动画期间,z轴似乎不会改变。在以下示例中,应将悬停的元素置于顶部,但是#element_a仍然在顶部。
如果我为常规选择器和:hover选择器添加一个z-index,它似乎可以工作,并允许悬停元素处于最顶层。
虽然这不完全符合您的要求,但这种行为提供了一种解决方案。您只需要使用translate3d和z-index来设置初始渲染的顺序即可。
<style>
    div {
        width: 300px;
        height: 150px;
        background-color: white;
        border: 5px outset gray;
        float: left;
        margin: 20px;
        -webkit-transition: 2s;
    }

    #element_a {
        -webkit-transform: translate3d(0, 0, 50px);
    }
    #element_b {
        -webkit-transform: translate3d(0, 0, 100px);
    }

    #element_a:hover {
        -webkit-transform: translate3d(100px, 0, 60px);
    }

    #element_b:hover {
        -webkit-transform: translate3d(-100px, 0, -60px);
    }
</style>
<body>
    <div id="element_a">
        <img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
    </div>
    <div id="element_b">
        <img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
    </div>
</body>

3
这对我有用-谢谢!我添加了以下内容到我想要置于前方的元素中:-webkit-transform: translate3d(0, 0, 1px); - Sam Dutton

1
我可以帮您翻译成中文。这段内容是关于iOS/iPhone上的编程问题,涉及到下拉菜单和leafletjs地图的重叠问题,发现地图应用了translate3d属性。为解决该问题,在下拉元素中添加了以下内容:
transform: translate3d(0,0,0);

......并且已经修复了。感谢stackoverflow的人们。


0
另外一种解决方法是您可以创建一个父元素,并将所有其他相关转换应用于它:
# Apply transitions to a parent div
<div>
  # This image z-index -1 
  <img src="foo"/>

  # This image z-index -3
  <img src="bar"/>

  #This image z-index -2
  <img src="gg"/>
</div>

JsFiddle


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接