不简单的 z-index
1. 关键概念
1.1 层叠顺序
层叠顺序,即在同一层叠上下文中的排序规则:
形成层叠上下文的背景和边框
定位
的带有 负值z-index
的元素,该元素形成子的层叠上下文
非定位
的块级元素非定位
的浮动
元素非定位
的行内元素定位
的z-index
为0或者auto
元素定位
的z-index
大于0
元素
同一层叠顺序按照在HTML中出现的顺序层叠
1.2 形成层叠上下文的因素
根元素html
相对,绝对定位元素,且
z-index
不为auto
position:fixed的元素
,不关心z-index
的值z-index
不为auto
的flex项目,即父元素为display:flex|inline-flex
opacity
小于1transform
属性值不为none
mix-blend-mode
属性值不为normal
的元素filter
值不为none
的元素perspective
值不为none
的元素isolation
值为isolate
的元素will-change
中指定任意css属性-webkit-overflow-scrolling
属性值为touch
的元素
子元素的z-index值只在父级层叠上下文中有意义。没有创建自己层叠上下文的元素将被父级层叠上下文同化。
2. MDN文档分析
示例解释
因为div1-div5
祖先元素中只有html
产生了层叠上下文,即div1-div5
属于一个层叠上下文,符合以上规则。
div1-div4属于【6】:z-index
为0或者auto
的定位元素。div5属于【3】: 非定位
的块级元素。因此div5在div1-div4下面。
div1-div4同属于【4】,因此按照html中的顺序依次堆叠。
2.2 堆叠与浮动
示例解释
同样,div1-div5都属于html这个层叠上下文。
div1,div5 属于【6】:z-index
为0或者auto
的定位元素。
div2,div3属于【4】:非定位
的 浮动
元素。
div4属于【3】:非定位
的块级元素。
因此顺序是:div4,div2,div3,div1,div5。
疑问:当给div4设置opacity非1之后(产生层叠上下文),顺序成了div2,div3,div1,div4,div5.像是理解为div4成了定位元素。因此在div1与div5之间,因为HTML中出现的顺序是div1,div4,div5。
2.3 Adding z-index
示例解释
同样,div1-div5都属于html这个层叠上下文。
div1-div4同属于【7】:定位
的 z-index
大于 0
元素。
div5虽然有z-index
但是对于该元素为非定位
元素,所以无效,因此属于【3】:非定位
的块级元素。
在div-div4中,dom与z-index的关系:
因此最终顺序为:div5,div4,div3,div2,div1.
2.4 层叠上下文
示例解释
div1-div6都形成了层叠上下文,属于【2】:相对,绝对定位元素,且z-index
不为auto
。
div1-div3 父层叠上下文为html,即祖先元素中唯有html为层叠上下文。 div4-div6 父层叠上下文为div3,即最近的层叠祖先元素为div3。
因此层叠顺序为: div2, div3, div5, div6, div4, div1
示例解释
div1-div4都是定位元素,div1是div2父元素,div3是div4父元素。
此时因为div1-div4都没有生成层叠上下文,同属于html层叠上下文中,所以层叠顺序为: div1,div2,div3,div4。
因为在同一堆叠上下文中,故此时给div2或者div4设置z-index时,即会使得div2或者div4在其它元素之上。
示例解释
div1-div4都是定位元素,div1是div2父元素,div3是div4父元素。
div1-div3同属于html层叠上下文,div4属于div3层叠上下文:
因此层叠顺序为: div1,div3,div4,div2
示例解释
dom结构:
一级菜单level1相对定位,但没有产生层叠上下文。
此时如果container1没有产生层叠上下文,则level2与level1同属html层叠上下文。此时根据HTML中出现的顺序,第一个level1下的level2会出现在第二个level1下面。
为使得所有level2出现在所有level1上面,则可以给level2设置z-index,(level2产生了层叠上下文)。同一层叠上下文下,z-index决定层级。
示例解释
即 red,green,blue 都是绝对定位,且它们的父级div1-div3都没有形成层叠上下文,所以所有的元素同属于一个html的层叠上下文,因此给.red添加z-index会使得该元素显示在green和blue上面。
为了让red显示在green,blue下面,首先根据html出现顺序,div1层级在div2和div3下面,则只要保持层级不变,同时让div1变成层叠上下文,则.red的层级作用在div1上,即能让.red在div2,div3下面。
2.9 antd中的弹窗类组件
antd中一些弹出类的组件,假如结构:
即使你给modal很高的层级,可能仍然覆盖不了123: 比如这种情况:
此时div1的层级必然小于div2,则Modal的层级z-index再大也没效果,都不能覆盖123。此时的解决办法是让div1的层级大于div2的层级。比如:
但此时得确保div.div2的层级小于div1,即不能设置定位且z-index>=1. 否则123又会被覆盖。
基于以上的所有情况,最好的办法就是antd那样,将Modal的实际DOM作为body的直接子元素,加在body的最后。
注意:只有z-index会影响层叠顺序,opacity只是创造层叠上下文,不会改变层叠顺序,因此:
3. 参考资料及疑问
在2.2和2.9中分别有一处暂时不能解释的疑问
MDN:理解css的z-index属性 antd中弹窗类组件默认作为body子组件的参考 没人告诉你关于z-index的一些事 z-context chrome插件,分析元素的层叠上下文以及z-index
Last updated