今天遇到一个问题,就是使用了transform属性的元素,其子元素的z-index属性失效了。网上搜了很多信息,大致了解了这个问题的来龙去脉,来跟大家分享一波。
我们都知道,z-index可以通过设置数值大小,来决定层级高低,但一涉及transform,z-index就失效了,为什么呢?
一、原因
原来,web中的任何元素都存在于一个三维空间中,除了大家熟知的平面画布中的x轴和y轴之外,还有控制第三维度的z轴。元素在x轴和y轴上的表现,可以使用margin、float、offset这些属性来控制。而z轴上的表现,则可以通过z-index和transform等属性来控制。
z-index控制z轴,需要配合position属性,z-index的数值越大层级就越高。transform可以通过它的translateZ() 来改变元素的层叠顺序,值越大则层级越高。不过通过transform:translateZ() 改变元素z轴层级,必须在其父元素中设置transform-style:preserver-3d 或者在transform中设置perspective() 才有效。
有人可能会问,如果二者同时设置会怎样呢?原来,transform会创建比z-index更高层级的stacking context(堆叠上下文),所以z-index会失效。
二、堆叠上下文
css是层叠样式表,层叠上下文就是html文件渲染的时候,各个元素的堆叠规则,哪个元素在距离屏幕更近的层级,类似Photoshop中的图层原理,这也是css中非常重要的潜在规则。
所以,给元素设置transform属性会创建层叠上下文的一个新区域,原本的层叠规则就会发生变化,设置transform的元素就变成了一个层叠上下文容器,也就相当于处于最底层了。此时,它的子元素如果需要被点击,可能就会受到影响了。当然,它的兄弟元素或其他外层元素的层叠规则并不受影响。
三、创建新区域的方法
除了transform之外,还有哪些情况会创建新的区域呢?
- 根元素(HTML)
- 设置了position为absolute或relative,且z-index不是auto的元素
- 设置了z-index,且不为auto的流动元素
- 设置了opacity,且不为1的元素
- 设置了transform,且不为none的元素
- 设置了mix-blend-mode值,且不为normal的元素
- 设置了isolation 为 isolate的元素on mobile WebKit and Chrome 22+,
- 设置position为fixed的元素
四、解决方案
1. 避免使用transform属性,改为使用margin-left:(-width/2)属性来实现元素居中;
2. 给使用transform元素的父级增加transform-style: preserve-3d;
3. 给使用了transform元素显示的设置perspective()
4. 元素里再创建一个标签,应用新标签的before伪类,设置定位,以原来的元素为基准,top、bottom、right、left为0,以充满整个容器。注意,z-index的设置与原来元素的before、after中的z-index有关,必须比它的值大。
5. 使用pointer-events属性做穿透处理。
我的项目使用前几种方法都无效,最后尝试穿透处理就ok了。你遇到的问题呢?
网友评论