最近要实现一个类似下面的层叠的效果,需要带一个hover 缓动效果。

第一反应就是直接使用:before&:after伪元素,配合绝对定位加z-index 轻松实现,实际操作发现并不是这么一回事。

代码如下


.box{
    width:100px;
    height:100px;
    position:relative;
    z-index:2;
    box-shadow:0 3px 5px #eee;
    background-color:#fff;
}

.box:before{
    content:"";
    position:absolute;
    top:5px;
    left:5px;
    right:5px;
    bottom:-5px;
    box-shadow:0 3px 5px #eee;
    background-color:#fff;
    z-index:1;
}

但是得到的确实下面的效果

也就是:before 跑到上面来了,检查.box 也有postion 属性赋值,当时就有点懵逼了。因为和层叠有关,所以就翻了一些和z-index 相关的资料,也就是层叠顺序,网上相关资料很多,本文主要说说伪元素的层叠上下文。

解决方案

.box{
    width:100px;
    height:100px;
    position:relative;
    top:0;
    box-shadow:0 3px 5px #eee;
    background-color:#fff;
    transiton:.5s;
}

.box:before{
    content:"";
    position:absolute;
    top:5px;
    left:5px;
    right:5px;
    bottom:-5px;
    box-shadow:0 3px 5px #eee;
    background-color:#fff;
    z-index:-1;
}

.box:hover{
    top:-5px;
}

父元素不设置z-index值,伪元素设置负z-index 值,父元素位移效果不使用transform,简单说下原因。

  • 同一个层叠上下文里面, 层叠顺序从后向前依次是: 背景和边框、负z-index、块级盒、浮动盒、行内盒、z-index:0、正z-index.
  • 伪元素相当于子元素,也就是包含在元素内的,二者不在同一个层叠上下文中。

如果想实现层叠效果,需要元素和对应的伪元素在同一层叠上下文中,所以不能让元素创建层叠上下文。以下情况会创建层叠上下文

  • 即便是 position 不为 static 的元素, 如果没有指定一个非 auto 值的 z-index, 该元素就不会建立一个层叠上下文。
  • 元素的transform值不是none

当然还有其他情况本文就不列出了,因为transform 会创建层叠上下文,所以缓动的时候只能使用top 进行变换了。

这里有点的是,top bottom 等属性如果没有设置初始值transition是不会生效的,所以代码中设置了初始值top:0