写点什么

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

评论

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

Spring Bean处理器

语霖

Spring Framework

XSKY对象存储获全球备份领域领导者Commvault官方认证

XSKY星辰天合

区块链助力军事人力资源配置

CECBC

区块链 军事

SpreadJS 纯前端表格控件应用案例:MHT-CP数据填报采集平台

葡萄城技术团队

1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知

YourBatman

Hibernate-Validator Bean Validation 数据校验 JSR380

Cassandra Gossip协议的二三事儿

华为云开发者联盟

源码 三次握手 开发者 Cassandra Gossip协议

SpreadJS 纯前端表格控件应用案例:雨诺订单管理系统(雨诺OMS)

葡萄城技术团队

技术分享:即构互动白板音视频同步、多端有序协作技术实践

ZEGO即构

音视频 在线教育 SVG

关于显性知识和隐性知识

Tanmer

知识管理 知识产权

数字货币交易平台源码,数字货币交易所开发核心功能

13530558032

面试必备知识点:悲观锁和乐观锁的那些事儿

鄙人薛某

面试 乐观锁 悲观锁 CAS 并发控制

3种双集群系统方案设计模式详解

华为云开发者联盟

数据库 数据仓库 数据 双集群系统 双ETL模式

某程序员毕业进UC,被阿里收购!跳去优酷土豆,又被阿里收购!再跳去饿了么,还被阿里收购!难道阿里想收购的是他?

程序员生活志

职场 阿里

凡泰极客与Rancher达成深度战略合作,加速企业构建私有化小程序生态

FinClip

人的转型才是关键 数字化时代你具备数字领导力么

CECBC

区块链 数字化时代

云原生如何来进行HTTPS升级

soolaugust

架构 云原生 设计模式

从 Node.js(JavaScript) 到 Golang,我的开发体验

Garfield

node.js Go 语言

读懂k8s 容器编排控制器 Deployment

Garfield

k8s pod k8s入门

数字资产钱包开发,数字加密货币app搭建

13530558032

案例分享丨红外自动感应门设计与实现详解

华为云开发者联盟

物联网 传感器 感应探测器 SMT32处理器 感应门

华为云FusionInsight大数据技术普惠创新,释放千行百业数据价值

数据湖洞见

大数据 FusionInsight 华为云

MAC系统初始化

焦振清

macos 重装系统

LeetCode题解:155. 最小栈,单个栈存储入栈元素与最小值之差,JavaScript,详细注释

Lee Chen

大前端 LeetCode

融云Geek Online 2020 编程挑战赛重磅来袭

InfoQ_967a83c6d0d7

区块链支付新模式开发,USDT支付系统搭建

13530558032

anyRTC Native 4.1.0.1与Web SDK 4.0.11上线

anyRTC开发者

学习 WebRTC 语音 直播 sdk

挽救你的视频号:能够把PPT转换成视频,把备注转换成语音的开源项目

陈磊@Criss

话题讨论 | 当你敲代码累了时,一般喜欢吃点什么补充能量?

InfoQ写作社区官方

加班 写作平台 代码 话题讨论

你问我答:现有的应用有必要做微服务改造吗?

BoCloud博云

容器 DevOps 微服务 云平台 博云

深圳泰利能源有限公司涉嫌传销 共计2.7亿元

CECBC

区块链 基金

C语言内存泄露很严重,如何应对?

华为云开发者联盟

c 内存泄露 内存 代码 函数

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