z-index和transform你真的了解吗?

10116次阅读 413人点赞 作者: WuBin 发布时间: 2021-09-06 17:28:56
扫码到手机查看

堆叠上下文

z-indextransform是CSS中的属性,但很少同学将二者联系到一起,感觉他们八杆子打不上。事实真的是这样吗?如果你也不能确认,这篇文章就值得你花点时间阅读。因为阅读完了,你会有所收获的。

在开始今天的主题之前,先得回忆一下CSS中的Stacking Context(堆叠上下文)。因为只有了解清楚了这个概念,才能更好的了解下面的内容。

任何HTML文档默认的堆叠上下文都是<html>元素。因此,除非创建新的堆叠上下文。默认情况下,元素的堆叠顺序相对于页面内的其他元素。在一个未做堆叠顺序更换的页面中,其顺序就是根据HTML中的元素出现的先后顺序来决定,先出现的在底下,后出现的在顶部。用数字来表示的话是就1,2,3,4,...,n这样的顺序。

第二个div做了一个margin-top-50px,可以看到第二个div遮住了第一个div。那么怎么才能改变默认的堆叠顺序呢?

先把结论给大家抛出来,在CSS中可以使用z-indextransform可以改变元素的堆叠顺序。但也可能会导致一些奇怪的情况,比如具有较大的z-index的元素并不总是位于具有较低z-index元素的上方。比如,在一些情况之下,同时使用z-indextransform会让z-index失效等。

CSS中会产生新的层情况还有很多种:

  • 当一个元素位于HTML文档的最外层(<html>元素)

  • 当一个元素被定位了并且拥有一个z-index值(不为auto

  • 当一个元素被设置了opacitytransforms,filters,css-regions,paged media等属性

  • flex item,也就是父元素的display设置了flex或者inline-flex值,早期的box值不行

  • grid item,也就是父元素的display设置了grid或者inline-grid

  • isolation:isolate

  • 元素的mix-blend-mode值不为normal

  • 元素的overflow-scrolling值不为touch

  • 元素的filter值不为none

  • 元素的perspective值不为none

  • 元素的motion-path值不为none

三维空间

Web中的任何元素都存在于一个三维空间中,除了大家熟知的平面画布中的x轴和y轴之外,还有控制第三维度的z轴,如下图所示:

在CSS中使用margin,floatoffset这些属性,可以控制元素在x轴和y轴上的表现。而z轴上的表现形式可以通过z-indextransform来控制。

如何控制z轴

前面也说了,控制z是通过z-indextransform来实现的。先简单的了解一下这两种控制z轴的方法。

通过z-index控制z轴,需要配合position属性,且position的属性值为relativeabsolutefixedsticky时。并且给z-index显式的设置数值,数值越大,其层级越高。简单点说,数值越高,元素越在顶上。

transform可以通过它的translateZ()来改变元素的层叠顺序,其值越大,越在顶层,离屏幕越近。不过通过transform:translateZ()改变元素z轴的层级,必须在元素的父元素中显示的设置transform-style: preserve-3d或者在transform中显示的设置perspective()。如下所示:

有关于z-indextransform更多的教程可以阅读下面这些文章:

z-index 和 translate3d

特别声明:接下来的内容挑选于@凹凸实验室的《探究transform动画元素的z-index》一文。此文章详细讲解了transformz-index在一起使用将会发生的状况。

在一次需求中,需要做出三张卡牌走马灯式滚动的效果,由于在前面的一张卡牌需要挡住后面的卡牌,自然而然地就用z-index使前面的卡牌显示在最上面,配以transform动画让“走马灯”滚起来,在开发过程中,在 PC 侧 Chrome 中表现良好,在本人手机浏览器中也表现良好,最后测试时却发现,在微信客户端或 QQ 客户端中打开页面出现问题,“走马灯”滚动时,卡牌先通过transform就位后,才把z-index设置较大的卡牌置于上面,感觉上非常的不流畅。

究其原因,发现这是某些浏览器的渲染规则,涉及到 stacking context 的概念,transform的元素会创建新的 DOM,层级会在普通元素的上面,除了transform,还有哪些情况会创建新 stacking context呢?

很明显,红色div都在绿色div上面了,说明真的有创建了个更高层级的 stacking context。再做进一步测试,我给两组的div都加了position:relative;z-index:1;,结果绿色的都在上面了,手机微信上也一样,这能不能说明z-index对层级的影响大于transformopacity呢。

至于transform变换的时候会让z-index“临时失效”,其实并非z-index失效了,只是z-index被用在不同的 stacking context 上,而非在默认的 context 上同等地比较层级了。所以 DOM 在transform的工程中,DOM 处于一个新的 stacking context 里,z-index也是相对于这个 stacking context 的,所以表现出来的实际是 stacking context 的层次,动画一结束,DOM 又回到默认的 context 里,这时的z-index才是在同一个 context 上的比较。

那该用什么方法来控制卡牌的层级,又能让动画流畅地表现呢,当然是translate3d中的z-axis,很多时候我们并不知道它是用来做什么的,平常用得最多的只是它的x-axisy-axis

现在可以来理解下perspectivetranslate3d的关系,perspective可以比作镜头和 DOM 的距离,实际上设置多少都没影响,因为它通过跟z-axis上的数值比例来影响样式,它更像是一个刻度,而translate3dz-axis则表示了 DOM 和屏幕的距离。假定镜头跟屏幕的距离固定了,z-axis越大,DOM 逐渐远离屏幕,靠近镜头,这时 DOM 看起来也就越大,当z-axis大于或等于perspective时,DOM元素已经在我们镜头的后面了,所以也就看不到它了。

现在也就好理解为什么perspectivetranslate3d能够影响 DOM 的层级了,它们在屏幕和镜头之间的距离不同,所以就有了层次,移动端设备很好地表现了这个结论,但在 PC 的 Chrome 上测试则不然,我们仍需要z-index才会表现出我们需要的 层次关系。

transform变换z-index层级渲染异常

在一些浏览器或设备上,当transformz-index在一起使用时会发生异样,造成z-index失灵。至于为什么会失灵,以及如何解决,这里就不多讲了。如果您对这方面的感兴趣,可以看看@张鑫旭大师写得一篇文章《Safari 3D transform变换z-index层级渲染异常的研究》。

文章总结了两种解决方案:

  • 方法1:父级,任意父级,非body级别,设置overflow:hidden可恢复和其他浏览器一样的渲染

  • 方法2:以毒攻毒。也可以使用3D transform变换

至于怎么使用3D Transform,大家还是移步看张大师是怎么分析的

何时使用Transform来实现z-index

在介绍z-indextranslate3d一节中,我们也了解到了,有时候设置z-index来控制z轴并不有效,张大师文章也提到过,它们在一起使用时,有时候会使用z-index失灵。其实还有一个现象,大家可能平时并没有注意到。

当你通过z-index配合伪元素::before或者::after时让其z轴在元素的底部,特别是碰到大的元素渲染(比如全屏背景图),会直接影响性能,特别是在移动端,会造成客户端闪退,也就是大家所说的Crash,给用户造成非常不好的体验。

缩合上面的几个现象(当然可能还有很多我自己没有发现的),我们可以抛弃z-index来控制z轴的顺序,而是直接通过transform中的translateZ()或者translate3d()来控制z轴的顺序。

单独使用z-index或者transform中的translateZtranslate3d(),或许你都不会想到他们之间有这么多的故事,甚至更没有想到在实际业务中通过transform来替代z-index来控制元素的z轴的顺序。那么这篇文章介绍的就是这两者之间的故事,以及如何通过transform来控制元素z轴的顺序。

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:z-index,transform
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    9094次阅读 588人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    3845次阅读 287人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14071次阅读 914人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    12908次阅读 442人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    11469次阅读 920人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    15588次阅读 1244人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    14795次阅读 1205人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    28950次阅读 2273人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    24982次阅读 1925人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录