最近写了一个静态页面的时候,出现了一个不常见bug,布局在safari下会出现错乱,但是在firefox、chrome、甚至低版本的IE下都是正常的。仔细排查之后才发现原来是一个弹窗modal的z-index影响的,该弹窗css设置如下:
.dialog{
position: fixed;
z-index: -1;
top: 50%;
left: 50%;
overflow: hidden;
opacity: 0;
filter:alpha(opacity=0);
transition: all 300ms ease-in;
-moz-transition: all 300ms ease-in;
-webkit-transition: all 300ms ease-in;
-o-transition: all 300ms ease-in;
transform: scale3d(0.3, 0.3, 0.3);
-moz-transform: scale3d(0.3, 0.3, 0.3);
-webkit-transform: scale3d(0.3, 0.3, 0.3);
-o-transform: scale3d(0.3, 0.3, 0.3);
background: #fff;
box-shadow: 0px 0px 7px rgb( 0, 0, 0 );
border:1px solid rgb( 221, 221, 221 );
border-radius: 4px;
}
然后把z-index:-1;修改成z-index:0;之后就正常了。网上搜索了一下,才发现是Stacking Context这个影响的。
Css Stacking Context
——以下为翻译部分(https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context)
The stacking context是HTML元素的三维概念化的一个虚拟Z轴,它是与用户相对的视口或网页。HTML元素的堆叠优先级顺序是依赖元素的自身属性的。
给定位元素添加z-index,那么这些元素的堆叠顺序将会由z-index的值决定,这是因为这些元素具有了特殊的属性使它们形成了一个 stacking context。
在一个document的任何地方,任何元素都是可以形成stacking context。如下这些属性或元素将会形成一个stacking context。
- the root element (HTML),
- 定位元素(absolute、relative)的z-index值不是auto,
- 采用Flex布局的元素,Flex容器的所有子元素的z-index值不是auto,并且这个Flex容器的display: flex|inline-flex;的时候,
- 元素的opacity的值小于1的时候,
- 元素的transform的值不为none的时候,
- 元素的 mix-blend-mode的值不为normal的时候,
- 元素的filter的值不为none的时候,
- 元素的 perspective的值不为none的时候,
- 元素的isolation值为isolate的时候,
- 元素的定位为position:fixed;
元素的 -webkit-overflow-scrolling 值为 “touch”的时候。
Stacking Context的特性
stacking context可以嵌套
- 每个stacking context相对于兄弟元素是完全独立的,其内部规则不会影响到外部
- 每个stacking context元素都会被父stacking context当做一个元素施加stacking规则
对于一个stacking context内部的元素,如果这个元素没有形成stacking context,其z-index值是auto(但其实如果这个元素没有形成stacking context,z-index属性对这个元素的表现根本没有意义,我们可以理解为这个元素和其parent stacking context是一体的)。
我们通过给已定位元素(position: absolute or relative)指定z-index值以改变元素在其parent stacking context中Z轴的「相对偏移」量。这里的「相对偏移」指的是以parent stacking context为基准,相对于其它兄弟元素距离用户远近的顺序。
由于形成stacking context的元素其z-index属性并不对内部元素产生影响,因此其子元素以其(parent stacking context)为z-index相对基准点即z-index: auto,这些子元素的stacking context兄弟元素按照下面的远近顺序展示在屏幕:
远 ---------> 近
parent stacking context >> z-index < 0 >> 非stacking context元素(z-index: auto) >> z-index >= 0
*注意在stacking context中的元素不会远于parent stacking context
如果一个元素不是通过「定位」(position: absolute or relative)实现了stacking context,它将会以z-index: 0(高于auto)被看待,因此无论如何更改非「定位」元素的z-index都是无效的。
虽然文档中只提到opacity less 1构成的stacking context被看做z-index: 0,但通过测试,可以发现其他非「定位」方式创建的stacking context拥有与opacity less 1一致的表现。
参考文章:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
https://segmentfault.com/a/1190000002783265