z-index和transform,你真的了解吗?_层叠顺序transform与zindex_风神修罗使的博客-程序员宅基地

技术标签: HTML5+CSS|CSS3  

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

堆叠上下文(Stacking Context)

在开始今天的主题之前,先得回忆一下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
  • 当一个元素被设置了opacity,transforms, 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,float、offset这些属性,可以控制元素在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的工作原理
  • 没人告诉你关于z-index的一些事
  • 你对position的了解程度有多少?
  • 十步图解CSS的position
  • CSS3 3D Transform
  • CSS3 2D Transform
  • Transform-style和Perspective属性

z-indextranslate3d

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

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

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

下图是对 transformopacity 的测试结果:
在这里插入图片描述
很明显,红色 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,不妨先看个例子:
在这里插入图片描述
实际效果是,看不到它们,然后我们再设置 perspective201px,这时可以很明显地看到,.box2 占据了整个屏幕,而.box1 宽高约为 200px,唯有设置 translate3d(0,0,0) 时,宽高才为 100px

现在可以来理解下 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轴的顺序。如果文章讲解的有不对之处,或者你碰到过更奇葩的现象,以及相关的解决方案,欢迎在下面的评论中与我们一起分享。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/WuLex/article/details/105769655

智能推荐

(Java实习生)每日10道面试题打卡——JVM篇 (三)_兴趣使然的草帽路飞的博客-程序员宅基地

临近秋招,备战暑期实习,祝大家每天进步亿点点!Day08有粉丝大佬要求更新有难度的,所以本篇总结的是 JVM 相关的面试题,后续会每日更新~1、Java中的异常体系Java 冲所有异常都来自顶级父类 Throwable。Throwable 下有两个子类 Exception 和 Error,用于表示程序出现了不正常的情况。区别在于:Error 是程序错误,通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这.

【机器学习】线性回归(超详细)_机器学习线性回归_无咎.lsy的博客-程序员宅基地

机器学习之线性回归,看懂这一篇就够了(超详细)。_机器学习线性回归

python使用setuptools打包egg_python setup egg_shirukai的博客-程序员宅基地

Python使用setuptools打包egg作为Python标准的打包及分发工具,setuptools可以说相当得简单易用。相面记录一下Python如何利用setuptools进行分发打包。安装Setuptools方式一:通过python安装wget http://peak.telecommunity.com/dist/ez_setup.pypython ez_setu..._python setup egg

路由策略简介_路由策略有哪几种_厦门微思网络的博客-程序员宅基地

如图2所示,SwitchA也是双上行的网络结构,但是,由于SwitchB这边的链路稳定性更好一点,带宽更大一点,因此用户想用SwitchB这边的链路作为主用链路,SwitchC这边的链路作为备用链路,当主用链路故障的时候流量自动切换至备用链路。这种场景下,可以使用路由策略,将来自SwitchB这边的路由开销值调小,将来自SwitchC这边的路由开销值调大,这样流量就会自动选取SwitchB这边的链路作为主用链路,SwitchC这边的链路作为备用链路,实现路由的主备份。通过路由策略修改路由的属性。..._路由策略有哪几种

python面向对象——01 类属性与对象属性,从月饼中得到领悟_第1关:学习-python面向对象之属性_刘知之的博客-程序员宅基地

python面向对象一、面向对象1、python面向对象与其他语言区别2、面向对象与面向过程3、总结二、类与对象的属性1、对象的属性对象属性的操作2、类属性3、属性的本质4、限定类的可添加哪些属性六、方法本人本来是写java的程序员,现在搞python自动化,有时候就感觉python好随意,很多地方都是凭感觉,虽然能实现工作中的大部分功能,但是一知半解,所以决心系统的学习一下python。这里面向对象是在B站上看一位up主的视频,他讲的真的非常好,我仅记录部分内容,截图很多[来自他的视频],(https_第1关:学习-python面向对象之属性

随便推点

int数组与List互相转换_int数组转list_AllenLeungX的博客-程序员宅基地

int[] data = {4, 5, 3, 6, 2, 5, 1}; // int[] 转 List<Integer> List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList()); // Arrays.stream(arr) 可以替换成IntStream.of(arr)。 // 1.使用Arrays..._int数组转list

skywalking指南—agent日志采集和插件_c. 在数据库服务器上安装agen插件采集-程序员宅基地

skywalking指南—agent日志采集和插件延续前两篇,完成skywalking的日志采集,并对插件版本及获取提供帮助_c. 在数据库服务器上安装agen插件采集

OkHttp 小记-程序员宅基地

文章目录常见面试问题一、主要构件二、基本使用依赖引入请求流程同步请求异步请求Builder 配置三、请求流程分析同步请求RealCalll.execute()Dispatcher.executed(call:RealCall)getResponseWithInterceptorChain 触发拦截器处理异步请求Call.enqueue(responseCallback: Callback)Disp...

Linux系统中的时间设置(硬件时钟VS系统时钟)_linux设置硬件时钟-程序员宅基地

在实际工作中,我们部署在linux系统中的应用的运行通常需要使用正确的时间,而在没有时钟同步服务的时候,就需要我们手动去修改linux的系统时间。那么这里就说说如何修改linux的系统时间。软件时钟软件时钟就是linux操作系统的时钟,我们可以使用date命令查询出时钟的时间。对于它的设置,可以使用命令date -s "2022-04-15 14:00:00"。硬件时钟硬件时钟是存储在服务器主板上,由主板电池为其供电的时间记录模块,可以通过hwclock --show来查询当前的硬件时间。如果通过上_linux设置硬件时钟

hashCode()和System.identityHashCode的区别_system.hashcode_学习进行时!的博客-程序员宅基地

hashCode是根据对象的地址生成的哈希值,只要判断出两个对象的hashCode不一致,就知道两个对象不是同一个我运行的代码 Student s1 = new Student(18,"Kang"); Student s2 = s1; System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(System.identityHashCode(s1_system.hashcode

推荐文章

热门文章

相关标签