• 中文
  • ENGLISH
chrome中position:fixed对z-index的影响
2016/04/01

先看这样一个需求

页面如图:

div A是一个悬浮磁条,固定宽度居中。有个子元素A-child右浮动。浏览器向下滚动时实现下图效果:

B挡住A,A-child挡住B。

dom结构:

正常的实现方式很容易:因为B本身就在A的后面,当A和B都设置了position属性(非static),且没有设置z-index的时候,其层叠关系是后面的元素覆盖前面的元素,这样只需要给A-child设置z-index属性值即可。less代码:

#wrap{
  position: relative;
  width: 1200px;
  margin: 0 auto;
  height: 100%;
  text-align: center;
  color:#000000;
  font-size:50px;
  #a{
    position: fixed;
    top: 50px;
    width: 950px;
    height: 100px;
    background-color: red;
    padding: 20px;
    #a-1{
      position:relative;
      font-size:30px;
      float:right;
      width:100px;
      height:100px;
      background-color: #cc0000;
      z-index: 1;
    }
  }
  #b{
    position:absolute;
    left: 0px;
    top:550px;
    background-color: #0000f6;
    width: 990px;
    height: 100%;
  }
}

出现的问题

除chrome浏览器以外,IE8+和其它浏览器效果正常(当然IE6,7也有问题)。chrome下如图:

A-child无法覆盖B元素。

原因

后来发现是chrome22+以后的一个改动,参考链接:The stacking context

关键内容:

这段话主要说明在什么情况会创建层叠上下文(The stacking context)。

红线部分说的就是移动端webkit的浏览器和chrome22+的浏览器,position:fixed的时候也会创建一个层叠上下文。这里面层叠上下文的概念很重要,z-index的相关内容很多,如果对z-index的使用不清楚,可先参考这篇文章:CSS z-index 属性的使用方法,z-index详细内容可参考如下系列文章:Understanding CSS z-index

chrome的这个改变就会造成A元素形成一个新的层叠上下文,并且当成一个整体在父层叠上下文中进行比较,A-child因为设置了z-index属性,所以也会创建一个层叠上下文,但是它的父层叠上下文变成了A,所以它只能在A的内部进行层叠比较。这也就是很多文章中所说的“从父原则”。其它的浏览器,position:fixed不会创建层叠上下文,因此整个页面只有root和A-child两个层叠上下文,所有层叠元素都在root层叠上下文中进行比较。

chrome浏览器这种变动的原因

我的理解就是为了在移动端浏览器滚动时达到性能最优化,使得页面有更强大的响应性。我想其性能提升可能体现在页面滚动渲染的时候,position:fixed的元素当成一个整体的层叠上下文进行比较,而不需要考虑其内部子元素和整个页面其它部分的层叠关系,但是我并未感觉这会带来多大的提升……。而PC端之所以改变是为了不和移动端相悖而产生两个版本。

参考资料:Stacking Changes Coming to position:fixed elements

解决方案

想过一些解决方案,比如只fixed定位A-child元素,但是在响应式的时候对于始终右浮动的定位计算很麻烦,且需要resize事件不断计算。

最终灵机一动想到一个办法:很简单,当滚动到蓝色区域时,设置A元素的z-index,让它覆盖B元素,同时把A元素的高度设为0,只让A-child显示出来;也可以设置A的visiblity:hidden,A-child的visiblity:visible(opacity代替visible不可以)。less代码:

#wrap{
  position: relative;
  width: 1200px;
  margin: 0 auto;
  height: 100%;
  text-align: center;
  color:#000000;
  font-size:50px;
  #a{
    position: fixed;
    top: 50px;
    width: 950px;
    //height: 100px;
    height:0;
    background-color: red;
    //padding: 20px;
    z-index:1;
    #a-1{
      position:relative;
      font-size:30px;
      float:right;
      width:100px;
      height:100px;
      background-color: #cc0000;
      //z-index: 1;
    }
  }
  #b{
    position:absolute;
    left: 0px;
    top:550px;
    background-color: #0000f6;
    width: 990px;
    height: 100%;
  }
}

总结

chrome浏览器和移动端基于webkit的浏览器,position:fixed会创建新的层叠上下我,注意对样式的影响。

关于z-index几点常见问题

  1. z-index只有在设置了position为relative,absolute,fixed时才会有效。
  2. z-index的“从父原则”。当你发现把z-index设的多大都没用时,看看其父元素是否设置了有效的z-index,当然别忘了先看看自身是否设置了position。
  3. 不要乱用z-index,否则层叠关系会把你搞晕,且难以维护。只在必要的情况下设置,目前我想到的必要的时候只有:悬浮层、负margin产生的覆盖情况。

position:fixed

发现position:fixed不设置left,top的时候,其默认值并非0,0。而是根据其父元素边界确定的,请自行测试,还未具体查看资料。

opacity和visiblity

设置父元素透明,再设置子元素不透明将失效。设置父元素不可见,再设置子元素可见,可以成功。

订阅我们