CSS层叠顺序和层叠上下文

2016年12月11日Web前端0

在用CSS布局的时候,经常会遇到元素叠加元素的情况。当然,我们会很好奇,为什么这个浮动元素会叠加到另一个元素的上面显示,而在其他时候浮动元素又是被覆盖的呢。

层叠顺序

层叠顺序是指元素重叠时,他们显示的顺序。以下图可以反应这一显示关系。

2016-05-16_170222

W3C官方对这7层的说法是:

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants.
  4. the non-positioned floats.
  5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  7. the child stacking contexts with positive stack levels (least positive first).

翻译成中文的话,

  1. 形成堆叠上下文环境的元素的背景与边框。
  2. 拥有负 z-index 的子堆叠上下文元素 (负的越高越堆叠层级越低)。
  3. 正常流式布局,非 inline-block,无 position 定位(static除外)的子元素。
  4. 无 position 定位(static除外)的 float 浮动元素。
  5. 正常流式布局, inline-block元素,无 position 定位(static除外)的子元素(包括 display:table 和 display:inline )。
  6. 拥有 z-index:0 的子堆叠上下文元素。
  7. 拥有正 z-index: 的子堆叠上下文元素(正的越低越堆叠层级越低)。

注:定位元素默认z-index是auto,可以看成z-index:0。 关于层叠顺序的总结,

  • 两个同类型的元素重叠时,默认后一个比前一个层级高。
  • 在没有设置背景的情况下,元素的背景色是透明的,且允许后面的元素透上来。
  • 块级元素和其他任意除定位元素以外,文字层级比背景层级高。
  • 行内块层级大于浮动层级大于块元素的层级。
  • 后一个定位元素的层级大于前一个定位元素。
  • 定位比所有的元素层级都高。

层叠上下文

至于为什么会产生这种效果呢?都是层叠上下文照成的效果。

在HTML 中有个三维概念,我们观看电脑屏幕的实现可以被视为Z轴(层叠轴)。元素越在Z轴的前面,越是离用户近。 对于相同层叠上下文的层叠排列,就需要用到z-index了,z-index越高,层级就越高。

当然,我们如何才能出发层叠上下文呢?

  • 根元素
  • z-index值不为auto的绝对/相对定位
  • z-index值不为auto的flex项目
  • opacity属性值小于1的元素
  • transform属性值不为none的元素
  • mix-blend-mode属性值不为normal的元素
  • filter值不为none的元素
  • perspective值不为none的元素
  • isolation属性被设置为isolate的元素
  • position属性值为fixed
  • -webkit-overflow-scrolling 属性被设置 touch的元素
  • 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值

以上情况下,对元素在视觉上没有啥影响,但是回创造新的层叠上下文。

在层叠上下文中,其子元素同样也按照上面解释的规则进行层叠。其中,若一个父元素的z-index低于另一个同级的元素,其子元素的z-index再高也没有用。且,每个层叠上下文在他的父层叠上下文中都以一个普通元素来对待,其内部的层叠规则不影响其本身在其父层叠上下文中的层叠顺序。

注:不同层叠上下文之间互相独立,互不影响。

根据图,我们可以很容易的实现这种情况,css样式是:

.one {
    height: 200px;
    width: 200px;
    background-color: red;
    z-index: -1;
}
.two {
    height: 200px;
    width: 200px;
    background-color: blue;
    display: block;
    margin-