transform引起的stacking context问题

836 阅读3分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

需求背景

  1. 游戏界面有按钮浮层,浮层层级高于游戏画面层级,按钮可点击;
  2. 游戏界面可切换横竖屏,竖屏使用CSS3属性——transform:rotate(-90deg);方法旋转游戏画面。

bug描述

游戏在竖屏模式下,视频开关按钮显示不完整,且无法点击;游戏在横屏模式下,视频开关按钮显示完整,且可正常点击。

第一轮问题分析

小白:也就是横屏没问题,竖屏有问题?

小白:“按钮显示不完整且无法点击”?可能是层级问题,层级问题好解决啊,加个z-index试试,z-index:9999;

小白:???咦,怎么没生效?再大一点!z-index:9999999999;

第二轮问题分析

小白:横竖屏的区别只是在于屏幕旋转,所以问题可能出在transform:rotate(-90deg)方法上。

设置transform会产生什么影响?

  • 给DOM设置transform属性会创建一个新的stacking context(层叠上下文),使得原本的层叠规则发生变化,导致了设置了transform的元素变成了一个层叠上下文容器,层叠上下文容器的堆叠水平比普通元素高。这也就是为什么原本层级比较高的按钮会被遮挡住的原因。
  • 给一个元素加上transform效果后,它的子元素的z-index就“失效了”;其实并非z-index失效了只是z-index被用在不同的stacking context上;DOM在设置transform属性后,会处于一个新的stacking context里,z-index也是相对于这个stacking context的,所以这个时候无限加大z-index的值并不会达到预期效果。

解决办法

使用transformtranslateZ(*z*)方法,在旋转的同时,设置其Z轴属性为0——transform:"rotate(-90deg) translateZ(0);将其所在的层叠上下文又会回到原来的位置,此时游戏画面层级不会覆盖按钮层级,问题完美解决。

相关知识背景

stacking context(层叠上下文)

堆叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

如何触发元素的堆叠上下文

  • 根堆叠上下文(我们所有的元素排序都是在此上下文中进行的)

  • z-index值为数值的定位元素的传统堆叠上下文

  • CSS属性引起的

z-index值不为auto的flex项(父元素display:flex|inline-flex)

元素的opacity值不是1

元素的transform值不是none

元素mix-blend-mode值不是normal

元素的filter值不是none

元素的isolation值是isolate

will-change指定的属性值为上面任意一个

元素的-webkit-overflow-scrolling设为touch