写点什么

CSS 层叠上下文和层叠顺序原理分析及实战

作者:王丹丹

  • 2020-06-28
  • 本文字数:4082 字

    阅读完需:约 13 分钟

CSS层叠上下文和层叠顺序原理分析及实战

1. 问题现象

最近在做一个网站的首页,首页的右上角有一个绝对定位的大动画,同时首页还有三个小动画,小动画部分的效果是:鼠标滑入特定区域(如下图),展示动画。


由于 UI 提供的动画画布很大,所以遮盖住了下图所示特定区域的 div 元素;最外层 div 元素,包括三个部分:头部标题、设置了透明度的文本以及一段文本。


在 div 元素上设置 onmouse 事件后,诡异的事情发生了:只有鼠标滑入设置透明度的文本时,小动画才出现,滑入其他部分,小动画不出现。


这是为什么?



探究原因,是因为大动画部分设置了绝对定位以及 z-index,形成了层叠上下文,层叠水平高于普通元素,遮盖了 div 中的部分元素。


要解决上述问题,咱们需要先翻开书本,从层叠上下文和层叠顺序说起。

2. 层叠相关概念和原理

2.1 层叠上下文

它是一个三维的概念,在 CSS2.1 规范中,每个盒模型都可看做一个三维空间,分别为平铺在画布上的 X 轴、Y 轴以及表示层叠的 Z 轴。一般情况下,元素在页面上沿 X 轴 Y 轴平铺,用户察觉不到它们在 Z 轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。


如果一个元素含有层叠上下文,那么这个元素则为层叠上下文元素。我们可以理解为这个元素比普通元素在 Z 轴上距离用户更近一些。


层叠上下文规则:


  • 层叠上下文的层叠水平比普通元素要高;

  • 层叠上下文可以嵌套,内部层叠上下文及其子元素的层叠水平受制于外部的层叠上下文;

  • 层叠上下文和其兄弟元素相互独立,即在不同的层叠上下文中,元素的层叠顺序没有可比性;

  • 不同的层叠上下文元素发生层叠的时候,元素的层叠水平由父级层叠上下文的层叠顺序决定;

2.2 层叠等级

在同一个层叠上下文中,它描述定义的是该层叠上下文中的层叠上下文元素在 Z 轴上的上下顺序。


当然,在普通元素中,也可以有层叠顺序,这时它描述定义的是这些普通元素在 Z 轴上的上下顺序。z-index 属性可以影响层叠水平,注意是“影响”,不是“决定”。

2.3 层叠顺序

以上的层叠上下文和层叠等级是概念,层叠顺序是指元素遵循的规则。在同一个层叠上下文中,其中的元素遵循下图的规则:



其中,border/background 为装饰属性,float 浮动盒子和 block 块状元素一般用作布局,inline/inline-block 内联元素包含的是网页内容。在网页中内容最重要,所以 inline/inline-block 的层叠等级顺序更高。


通过实例验证上述规则,结论如下:


1)负 index 的层叠等级大于层叠上下文、小于 block 块级水平盒子


可参考下文中"一些新的 css 属性会形成层叠上下文"中的第一个例子;


2)float 浮动盒子的层叠等级大于 block 水平盒子



<div style="background: green;width: 100px;height: 100px;float: left"></div><div style="margin-left: -30px;width: 400px;height: 50px;background: red">111111111111</div>
复制代码


3)inline/inline-block 水平盒子的层叠等级大于 float 浮动盒子



<div style="background: green;width: 100px;height: 100px;float: left"></div><span style="margin-left: -30px;background: red">111111111111</span>
复制代码


4)不依赖于 z-index 的层叠上下文的层叠等级大于行内元素的层叠等级(注:此处由于 opacity 属性,形成层叠上下文)



<span style="background: green;display:inline-block;width: 100px;height: 100px;opacity:0.8;vertical-align: middle;"></span> <span style="margin-left:-30px; background:red;vertical-align: middle;">111111111111</span> 
复制代码


5)正 index 的层叠等级大于不依赖于 z-index 的层叠上下文的层叠等级



<span style="background: green;display:inline-block;width: 100px;height: 100px;opacity:0.8;vertical-align: middle;"></span> <span style="margin-left:-30px; background:red;vertical-align: middle;position: relative;z-index: 4">111111111111</span>
复制代码

2.4 层叠准则

  • 在同一个层叠上下文中,如果元素具有明显的层叠水平标识时(如 z-index),层叠水平高的元素在上面,距离用户“最近”;

  • 当两个元素的层叠水平一致、层叠顺序相同时,DOM 流后面的元素会覆盖前面的元素

2.5 层叠上下文的形成

1)页面根元素,本身就具有层叠上下文,称为根层叠上下文


2)定位元素的 z-index 为数值时会形成层叠上下文


  • z-index:auto 时



<span style="background: green;display:inline-block;width: 100px;height: 100px;opacity:0.8;vertical-align: middle;"></span> <span style="margin-left:-30px; background:red;vertical-align: middle;position: relative;z-index: 4">111111111111</span>
复制代码


z-index:auto 时未形成层叠上下文,绿色长方形的 z-index 较大,所以绿色长方形遮盖了红色长方形;


  • z-index 的值为数值时



<div style="position: relative;z-index: 2;">    <div style="background-color: red;width: 100px;height: 200px;position: absolute;z-index: 1">
</div></div><div style="position: relative;z-index: 1;"> <div style="background-color: green;width: 200px;height: 100px;position: absolute;z-index: 2">
</div></div>
复制代码


z-index 的值为数值,形成了层叠上下文,绿色和红色长方形的父元素的层叠等级相比,红色长方形父元素的层叠等级更高,所以红色长方形遮盖了绿色长方形。


以上印证了:不同的层叠上下文元素发生层叠时,元素的层叠水平由父级层叠上下文的层叠顺序决定,同时也印证了 z-index 属性可以影响层叠水平,只是影响,不能决定。


3)一些新的 css 属性会形成层叠上下文


  • 元素为 flex 项,z-index 为数值


z-index 为数值的 flex 项,要满足两个条件,父级元素为 flex 或 inline-flex 布局,子元素的 z-index 为数组,方可形成层叠上下文。


情况 1:当父级元素不为 flex 或 inline-flex 布局时



<div>    <div style="background-color: red;width: 100px;height: 200px;z-index: 1">        <div style="background-color: green;width: 200px;height: 100px;position: relative;z-index: -1">        </div>    </div></div>
复制代码


在同一个层叠上下文中,负 index 的层叠顺序小于 block 块级元素,所以,红色长方形覆盖在绿色长方形的上面;


情况 2:当父级元素为 flex 或 inline-flex 布局时



<div style="display: flex;">    <div style="background-color: red;width: 100px;height: 200px;z-index: 1">        <div style="background-color: green;width: 200px;height: 100px;position: relative;z-index: -1">        </div>    </div></div>
复制代码


当最外层父级 div 元素 display:flex 时,第二层 div 元素 z-index:1(数值),则第二层 div 元素为层叠上下文,由下图的层叠顺序规则可知,负 index 的层叠顺序大于层叠上下文,所以绿色长方形覆盖在红色长方形的上面。



  • opacity


当 opacity 值不为 1 时,可形成层叠上下文


情况 1:当外层 div 元素未加透明度 opacity 时



<div style="background-color: red;width: 100px;height: 200px">    <div style="background-color: green;width: 200px;height: 100px;position: relative;z-index: -1">    </div></div>
复制代码


在同一个层叠上下文中,负 index 的层叠顺序小于 block 块级元素,所以,红色长方形覆盖在绿色长方形的上面;


情况 2:当外层 div 元素加了透明度 opacity 时



<div style="background-color: red;width: 100px;height: 200px;opacity: 0.5">    <div style="background-color: green;width: 200px;height: 100px;position: relative;z-index: -1">    </div></div>
复制代码


当最外层父级 div 元素 opacity:0.5 时,子元素的 z-index:-1,由层叠顺序规则可知,负 index 的层叠顺序大于层叠上下文,所以绿色长方形覆盖在红色长方形的上面;


  • 其他属性


transform 不是 none、mix-blend-mode 不是 normal、filter 不是 none、isolation:isolate 和-webkit-overflow-scrolling:touch,都可形成层叠上下文,此时与 opacity 值不为 1 的情况相同。

3. 解决办法

针对文章开篇提到的问题,有三种解决方案:


方案一:给外层 div 元素设置 position:relative,使 div 元素和绝对定位大动画的层叠水平相等


元素一旦成为定位元素,其 z-index 就会自动生效,且默认值为 auto,也就是 0 级别。由于绝对定位的大动画的 z-index 为 0,也就意味着层叠上下文的大动画元素和 div 定位元素是一个层叠顺序的。


于是当他们发生层叠时,遵循层叠准则第二条,div 元素可正常响应鼠标划入事件。


方案二:通过设置外层 div 元素 position:relative,z-index 为非 auto,形成层叠上下文


当 z-index 的值大于等于绝对定位的大动画的 z-index 值时,当他们发生层叠时,遵循层叠准则第一条,div 元素可正常响应鼠标划入事件。


方案三:通过设置父元素 display: flex|inline-flex,子元素作为 flex 项,z-index 值是不为 auto 的数值时,子元素可形成层叠上下文


可给外层 div 元素设置 diaplay:flex 属性,内层元素设置 z-index 不为 auto,则内层元素为层叠上下文元素,遵循层叠准则第二条,div 元素可正常响应鼠标划入事件。


以上方案是基于绝对定位大动画的 z-index 为 0 时。若绝对定位大动画的 z-index 值大于 0 时,方案一就不生效了,方案二和方案三的 z-index 需大于等于大动画的 z-index 值。

4. 总结

一旦普通元素具有了层叠上下文,其层叠顺序就会变高。它的层叠顺序依赖以下两个原则:


  • 如果层叠上下文元素不依赖 z-index 数值,则其层叠顺序 z-index:auto 可看成 z-index:0 级别;

  • 如果层叠上下文元素依赖 z-index 数值,则其层叠顺序由 z-index 值决定


当遇到页面中有元素发生重叠,或者元素不能正常响应鼠标等事件时,可检查下该元素以及其父元素和兄弟元素所在的层叠上下文。遵循文中所说的规则,设置对应的 css 属性,改变元素层叠顺序,即可解决相应的问题。


本文转载自公众号贝壳产品技术(ID:beikeTC)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzIyMTg0OTExOQ==&mid=2247485712&idx=2&sn=d788cf74f5d806636d54b6fd30b6025f&chksm=e8373a60df40b3763973faddf3d4db114591a07b3c4158ee1f939aefcab057e5afb939ada720&scene=27#wechat_redirect


2020-06-28 14:073023

评论

发布
暂无评论
发现更多内容

罗格科技:全球税务服务领域初露锋芒 罗格罗拉国际税大模型发布

科技热闻

解锁极致性能:Arm Cortex-X925 IPC 提升15%,终端用户体验感再突破

新消费日报

智算基石全栈加速,百度百舸 4.0 的技术探索和创新

百度Geek说

百度 大模型 技术 优化体系

火山引擎边缘智能×扣子,拓展AI Agent物理边界

火山引擎边缘云

1688电商生态新引擎:商品详情API引领行业发展新篇章

代码忍者

pinduoduo API API 性能测试

堡垒机价格贵吗?一定要买堡垒机吗?

行云管家

网络安全 堡垒机 数据泄露

橱窗LED透明屏:展示和广告的新宠

Dylan

广告 制造 LED display LED显示屏 市场

揭秘京东商品详情一键获取的API之旅

代码忍者

pinduoduo API API 性能测试

OCR+PDF解析配套前端工具开源详解!

合合技术团队

#开源 #前端 ODR

同风起,耀星河!华为携手伙伴一起创造无限可能

HarmonyOS开发者

HarmonyOS

大数据存储计算平台EasyMR:多集群统一管理助力企业高效运维

袋鼠云数栈

MQTT vs HTTP:谁更适合物联网?

EMQ映云科技

物联网 HTTP mqtt emqx

用豆包MarsCode 和CozeAPI接口全自动做一个文生图组件

TRAE

人工智能 大数据 AI Chat

国内外大模型应用的现状与未来:以ChatGPT、Mixtral和Llama为例

测吧(北京)科技有限公司

测试

开源大模型的私有部署:Llama与千问的比较研究

测吧(北京)科技有限公司

测试

除了deadline,我们还能用什么驱动开发?

思码逸研发效能

程序员 DevOps 软件开发 编码 IT 运维

测试流程必须严格执行吗?

老张

软件测试 验收测试 质量保障 流程规范

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

JackJiang

即时通讯;IM;网络编程

Kafka集群升级项目实施方案,打造高效数据处理平台

敏捷调度TASKCTL

kafka hadoop cloudera 集群 大数据运维

得物一面,都是非常经典的问题

王中阳Go

Go 面试 后端

零信任身份安全的基本原则

芯盾时代

身份安全 零信任模型

国际开发者成为 Apache IoTDB Committer,新视角谈开源经验!

Apache IoTDB

数据库 开源 时序数据库 IoTDB Apache IoTDB

社区周刊·Vol.182

华为云开发者联盟

开发者 华为云

智能体Agent应用的前沿:图文、短视频与流程图的生成技术

测吧(北京)科技有限公司

测试

智能合约与大语言模型的结合:未来的应用场景探索

测吧(北京)科技有限公司

测试

25个Linux系统性能调优技巧

威哥爱编程

Linux 系统调优

大模型在商业领域的应用:如何提升决策效率与用户体验

测吧(北京)科技有限公司

测试

检索增强生成(RAG)技术在知识图谱中的应用:Neo4j的探索

测吧(北京)科技有限公司

测试

文生图与文生视频:从文本到视觉的创作革命

测吧(北京)科技有限公司

测试

深度学习在视觉识别中的突破:从理论到实践

测吧(北京)科技有限公司

测试

AIGC技术的变革:语音识别与视觉识别的深度融合

测吧(北京)科技有限公司

测试

CSS层叠上下文和层叠顺序原理分析及实战_大前端_InfoQ精选文章