写点什么

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:072805

评论

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

Apache Doris + Paimon 快速搭建指南|Lakehouse 使用手册(二)

SelectDB

数据湖 Doris LakeHouse 湖仓一体 paimon

人工智能丨ReACT 推理提示

测试人

软件测试

杭州银行与平凯星辰联合荣获 2024 “金鼎奖”

先锋IT

平凯星辰亮相 2024 中国国际金融展,发布银行交易明细查询白皮书

PingCAP

金融 会议 TiDB 交易明细

杭州银行 x 平凯星辰 TiDB “行领柜面系统”荣获 2024 “金鼎奖”

PingCAP

安全 创新 金融 银行 TiDB

SIGGRAPH 2024 | 物理模拟领域再攀高峰!网易伏羲最新技术成果成功入选

网易伏羲

Python 算法

和鲸科技参与第17届中国R会议,分享有组织科研的模型生命周期管理

ModelWhale

人工智能 R 数据科学 AI4S

人工智能|ReACT 推理提示

霍格沃兹测试开发学社

【论文速读】| MoRSE:利用检索增强生成技术填补网络安全专业知识的空白

云起无垠

Qualcomm IPQ9574 and IPQ9554: The core choice to build Wi-Fi 7 high-performance routers

wifi6-yiyi

WiFi7 ipq9574

一文了解MySQL索引机制

京东科技开发者

微信小程序不备案有什么后果

源字节1号

小程序 开源 后端

如何定量分析 Llama 3,大模型系统工程师视角的 Transformer 架构

Baidu AICLOUD

Transformer llama GPU 利用率 推理并发

技术前沿|ICML 2024 中稿快讯!解锁大模型密态推理场景下的“百变怪”?

隐语SecretFlow

软考架构师必过的学习经验

源字节1号

小程序 开源 后端

Apache Doris 2.1.5 版本正式发布

SelectDB

倒排索引 Doris 半结构化数据 湖仓一体 物化视图

利用 Databend 生态构建现代数据湖工作流

Databend

IT外包服务成功案例分享与优势解析

Ogcloud

IT外包 IT外包公司 IT外包服务 IT外包企业 IT外包服务商

Apache Doris + Apache Hudi 快速搭建指南|Lakehouse 使用手册(一)

SelectDB

数据湖 Doris Hudi LakeHouse 湖仓一体

Solana行情为何坚挺?强劲基本面和ETF预期吸引资本流入

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

缓存框架 Caffeine 的可视化探索与实践

vivo互联网技术

Caffeine 缓存可视化 动态下发

TiDB Hackathon 2024丨用 TiDB 构建未来的 AI 创新应用, 瓜分超 ¥210,000 奖金池!

PingCAP

项目 hackathon TiDB 竞赛

强调数据价值,创建现代化全面预算管理系统

智达方通

企业管理 数据价值 数字化升级 全面预算管理系统

AI应用行业落地100例 | 移民公司Envoy Global引入AI员工赋能,效率飙升80%,开启服务新篇章

硅纪元

Java CompletableFuture 异步超时实现探索

京东科技开发者

【YashanDB知识库】update/delete未选中行时,v$transaction视图没有事务,alter超时问题

YashanDB

yashandb 崖山数据库 崖山DB

硅纪元视角 | Stability AI推出Stable Video 4D,40秒生成8角度动态视频!

硅纪元

Stable Video 4D Mistral Large 2 “Frame”眼镜 HoloDreamer

在 Go 中如何让结构体不可比较?

伤感汤姆布利柏

人类历史上首届AI选美,谁吃到了第一波AI审美红利?

脑极体

AI

防御性编程:让系统坚不可摧

京东科技开发者

100行代码手把手带你实现Feisitel加密算法

我再BUG界嘎嘎乱杀

Python 网络安全 安全 加密算法 Feisitel

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