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

  • 当一个元素被设置了opacitytransformsfilterscss-regionspaged 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()。如下所示:

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

z-index和transform,你真的了解吗?的更多相关文章

  1. 吃透css3之3d属性--perspective和transform

    本文为原创,转载请注明出处: cnzt 写在前面:最近写了个3d轮播效果图,在此将思路和过程中遇到的问题都记录下来. 首先,我们下来了解一下perspective和transform都是做什么的. t ...

  2. CSS3的变形transform、过渡transition、动画animation学习

    学习CSS3动画animation得先了解一些关于变形transform.过渡transition的知识 这些新属性大多在新版浏览器得到了支持,有些需要添加浏览器前缀(-webkit-.-moz-.- ...

  3. Animate与transform的使用

    Animate是用css给前端加载动画的效果: 网址:https://daneden.github.io/animate.css/ <!DOCTYPE html> <html lan ...

  4. SQL Server中LIKE %search_string% 走索引查找(Index Seek)浅析

      在SQL Server的SQL优化过程中,如果遇到WHERE条件中包含LIKE '%search_string%'是一件非常头痛的事情.这种情况下,一般要修改业务逻辑或改写SQL才能解决SQL执行 ...

  5. Transform.Translate 平移

    function Translate (translation : Vector3, relativeTo : Space = Space.Self) : void Description描述 Mov ...

  6. Unity Transform常识(转)

    Variables   position: Vector3  物体在世界坐标中的位置. transform.position=Vector3(10,10,10)//把物体放到(x=10,y=10,z= ...

  7. CSS3总结七:变换(transform)

    2D视图模型解析 3D视图模型解析 平移 旋转 伸缩 扭曲 z轴方向平移与perspective的神秘关系 matrix()终极变幻的方法 一.2D视图 2D视图就是默认平面上的每个点都与视线垂直,图 ...

  8. # Unity 游戏框架搭建 2019 (十六、十七) localPosition 简化与Transform 重置

    在上一篇我们收集了一个 屏幕分辨率检测的一个小工具.今天呢再往下接着探索. 问题 我们今天在接着探索.不管是写 UI 还是写 GamePlay,多多少少都需要操作 Transform. 而在笔者刚接触 ...

  9. [转]unity3d 脚本参考-技术文档

    unity3d 脚本参考-技术文档 核心提示:一.脚本概览这是一个关于Unity内部脚本如何工作的简单概览.Unity内部的脚本,是通过附加自定义脚本对象到游戏物体组成的.在脚本对象内部不同志的函数被 ...

随机推荐

  1. flutter showDatePicker显示中文日期_Flutter时间控件显示中文

    flutter showDatePicker showTimePicker显示中文日期 1.配置flutter_localizations依赖 找到pubspec.yaml配置flutter_loca ...

  2. 使用python3脚本部署mariadb主从架构

    环境准备 一个脚本自动部署master服务 另一个部署slave服务 关闭主从节点的防火墙 以及事先设置好root远程登陆的权限. master import paramikossh=paramiko ...

  3. sublime Text3文件路径提示功能

    1>启动sublime Text3编辑器: 2> 点开菜单“preferences”——“package control”: 3>在弹出的下拉框中选择“install package ...

  4. 在Eclipse Android中设置模拟器屏幕大小

    在Eclipse Android中设置模拟器屏幕大小是本文要介绍的内容,主要是来了解并学习Eclipse Android中模拟器的设置,具体关于Eclipse Android内容的详解来看本文. 方法 ...

  5. Docker 跨主机网络 overlay(十六)

    目录 一.跨主机网络概述 二.准备 overlay 环境 1.环境描述 2.创建 consul 3.修改 docker 配置文件 4.准备就绪 三.创建 overlay 网络 1.在 host1 中创 ...

  6. Python函数或者类的时间参数的默认值设为datetime.date.today()引起的问题

    定义了函数def main(start_date=datetime.date.today(), end_date=datetime.date.today()): pass 函数在项目启动后, end_ ...

  7. python __name__ == ‘__main__’详细解释(27)

    学习过C语言或者Java语言的盆友应该都知道程序运行必然有主程序入口main函数,而python却不同,即便没有主程序入口,程序一样可以自上而下对代码块依次运行,然后python不少开源项目或者模块中 ...

  8. c#,简单的冒泡排序

    冒泡排序 ,,,,,,,,,}; //bool IsSort; //do //{ // IsSort = true; // for (int i = 0; i < Nums.Length - 1 ...

  9. zabbix 批量添加web场景监控

    公司有大量测试环境的url需要监控是否能够访问,即url状态不为200即报警.状态为200即正常.因url比较多,且经常发生改变,如通过web场景配置(我没配过)会比较繁琐,工作量比较大.通过网上查找 ...

  10. [数据结构] - ArrayList探究

    一 概述 ArrayList可以理解为动态数组,与java的数组相比,它的容量能动态曾长,ArrayList是List接口的可变数组的实现,允许包括null值在内的所有元素.除了实现List接口外,此 ...