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

z-indextransform是CSS中的属性,但不多同窗将两者联系到一块儿,感受他们八杆子打不上。事实真的是这样吗?若是你也不能确认,这篇文章就值得你花点时间阅读。由于阅读完了,你会有所收获的。css

堆叠上下文(Stacking Context)

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

任何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值(不为autoflex

  • 当一个元素被设置了opacitytransformsfilterscss-regionspaged media等属性动画

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

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

  • 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()。以下所示:

上面的示例可能还不能明显的说明translateZ()改变堆叠上下文z轴的顺序,由于上面的代码有position设置,那你要是以为好奇,能够看下面这个示例。

示例左边的元素是没有设置translateZ,右边的元素设置了translateZ

有关于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呢?

下图是对 transform 和 opacity 的测试结果:

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

至于 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-axis 和 y-axis,不妨先看个例子:

实际效果是,看不到它们,而后咱们再设置 perspective 为 201px,这时能够很明显地看到,.box2 占据了整个屏幕,而.box1 宽高约为 200px,惟有设置 translate3d(0,0,0) 时,宽高才为 100px

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

如今也就好理解为何 perspective 和 translate3d 可以影响 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-index 和 translate3d一节中,咱们也了解到了,有时候设置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轴的顺序。若是文章讲解的有不对之处,或者你碰到过更奇葩的现象,以及相关的解决方案,欢迎在下面的评论中与咱们一块儿分享。

相关文章
相关标签/搜索