相邻元素的盒子阴影,且宽度不同

4

我想在两个元素上添加盒子阴影,每个元素的宽度都不同。我的期望结果如下:

screenshot

我一直试图通过伪元素覆盖重叠的盒子阴影来达到这个结果,但是因为它们需要透明度,我似乎找不到既没有盒子边缘小重叠也伪元素调整到正确宽度的解决方案。

顶部框架也不一定需要顶部边框来解决我的问题。

Fiddle

HTML:

<div>
    <p></p>
</div>
<div>
    <p></p>
</div>

SCSS:

div {
    display: inline-block;
    margin: 75px;
    width: 200px;
    height: 50px;
    position: relative;
    p {
        position: absolute;
        top: 100%;
        left: 0;
        height: 300px;
        width: 250px;
    }
    &, p {
        background: #ededed;
    }
}
div:last-child p {
    width: 150px
}

div {
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);
    p {
        box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);
    }    
}

编辑:

通常我不会考虑使用JS来进行布局,但在我的情况下,直到用户进行交互之前,这些框是不可见的,因此我使用了脚本来解决我的问题。当dom准备就绪时,脚本会计算出顶部元素是否比底部元素大,并分别向其添加“big”或“small”类。通过知道这一点,我们就知道了伪元素的宽度应该继承哪个元素。只要元素没有被调整大小以改变哪个元素更大,这个方法就可以正常工作。

如果只需要box-sizing模糊而没有扩散,也有一种更简洁的解决方案,无需使用JS并且少一个伪元素。

示例:

模糊和扩散组合(JS),

仅模糊,无扩散(无JS)

最终结果并不完美,如您在此截图中看到的,所有白色背景都被黑色取代:

Screenshot

当您查看左侧框的左上角时,您会发现边框阴影有轻微的曲线。无论如何,对我来说足够接近。

如果有人找到一个类似于第一个 fiddle 的仅使用 CSS 的解决方案,我会非常感激。


如果你的阴影很小,我建议直接使用 border,它看起来几乎相同,实现更简单,并且性能更好(在移动设备上尤为明显)。如果你选择使用投影效果,我认为将顶部元素的 z-index 放在较大元素后面应该可以让一切按照你想要的方式工作。 - Alexei Darmin
边框对我来说并不适用,因为它们的透明度是相对于它们所添加到的元素而不是其背景的。编辑 z-index 只能让您决定哪个元素的边框应该重叠在另一个元素上 尝试使用不同的背景颜色和子元素的负 z-index 进行实验 - Matthias
2个回答

2
你可以采用简单的解决方案,但它是一个实验性功能,并且支持有限。
使用过滤器:在基本元素上添加阴影,阴影应用于此元素及其所有后代的组合结果。

div {
    display: inline-block;
    margin: 75px;
    width: 150px;
    height: 50px;
    position: relative; 
    -webkit-filter: drop-shadow(0px 0px 5px rgba(255, 0,0,0.7));
    filter: drop-shadow(0px 0px 2px red);
}

div p {
    position: absolute;
    top: 100%;
    left: 0;
    height: 300px;
    width: 250px; 
    margin: 0px;
}

div, div p {
    background: #ededed; 
}

#second p {
  width: 100px; 
}
<div>
    <p></p>
</div>
<div id="second">
    <p></p>
</div>

另一种方法可以在任何浏览器中运行,使用伪元素的阴影:

div {
    display: inline-block;
    margin: 75px;
    width: 150px;
    height: 50px;
    position: relative; 
}

div p {
    position: absolute;
    top: 100%;
    left: 0;
    height: 300px;
    width: 250px; 
    margin: 0px;
}

div, div p {
    background: #ededed; 
}

#second p {
  width: 100px; 
}

div:after, p:after {
    content: "";
    position: absolute;
    left: 0px;
    top: 0px;
    right: 0px;
    bottom: 0px;
    box-shadow: 0px 0px 2px 6px rgba(0,255,0,0.7);
    z-index: -10;
}
<div>
    <p></p>
</div>
<div id="second">
    <p></p>
</div>

另一种方法是剪裁阴影。这种方法支持不佳,需要大量手动调整,但最终结果可能是最好的。 仅在Webkit中工作的演示。

div {
    display: inline-block;
    margin: 75px;
    width: 300px;
    height: 50px;
    position: absolute; 
}

div p {
    position: absolute;
    top: 100%;
    left: 0;
    height: 100px;
    width: 200px; 
    margin: 0px;
}

div, div p {
    background: #ededed; 
}


div:after, p:after {
    content: "";
    position: absolute;
    left: 0px;
    top: 0px;
    right: 0px;
    bottom: 0px;
    box-shadow: 0px 0px 15px 15px rgba(255,0,0,0.2);
    z-index: -10;
}

p:after {
    -webkit-clip-path: polygon(0% 30px, 230px 30px, 260px 60px, 100% 100%, 0% 100%);
}

div:after {
    -webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 260px 100%, 230px 80px, 0% 80px);
    
}
<div>
    <p></p>
</div>


谢谢你的回答,投影提示非常有用。但是如果你尝试使用伪元素方法并增加一些透明度,你会看到我在问题中提到的盒子边缘的小重叠:截图。 你有没有任何想法如何找到一个跨浏览器的解决方案,避免这些问题? - Matthias
这是一篇关于跨浏览器投影的好文章,适用于使用此方法的任何人:http://demosthenes.info/blog/600/Creating-a-True-Cross-Browser-Drop-Shadow-Effect-With-CSS3-amp-SVG - Matthias

0
如果你真的需要一个纯色背景而不是背景图片,可以这样做: 我使用了一个 div 来创建空白区域。
<div class="shad">
    <div class="cover1"></div>
    <p></p>
</div>

<div class="shad">
    <div class="cover2"></div>
    <p></p>    
</div>

段落的大小设置为与div.shad相同。

div.shad {
    display: inline-block;
    margin: 75px;
    width: 250px;
    height: 350px;
    position: relative;
    background: #ededed;
    p {
        position: absolute;
        top: 0%;
        left: 0;
        width: 250px;
        height: 350px;
    }
    .cover1 {
    position: relative;
    float: right;
    margin-top: -2px;
    margin-right: -2px;
    width: 50px;
    height: 50px;
    background-color: white;
    border-left: 2px solid rgba(0, 0, 0, 0.2);
    border-bottom: 2px solid rgba(0, 0, 0, 0.2);    
    }
    .cover2 {
    position: relative;
    float: right;
    margin-top: 50px;
    margin-right: -2px;
    width: 50px;
    height: 300px;
    background-color: white;
    border-top: 2px solid rgba(0, 0, 0, 0.2);
    border-left: 2px solid rgba(0, 0, 0, 0.2);
    }
}

div.shad {
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);     
}

这种方法并不能真正解决我的问题,因为它不能处理除白色以外的背景,并且遮罩div的边框实际上并没有显示.shaded元素后面的背景的阴影版本,而是遮罩元素的。我还需要元素的宽度是可变的,以便它们可以根据其内容的大小进行调整。使用不同颜色试验 - Matthias
从.cover1和.cover2中删除background-color。在定义背景颜色的位置添加.cover1,.cover2。body,.cover1,.cover2 {background:#7098BD;}这将解决着色问题。对于宽度,只需将宽度设置为%而不是px即可。 - Fionna
这对于静态颜色可以工作,但不适用于任何其他背景。我所说的可变宽度是指遮罩元素必须适应.shad元素的宽度,而该宽度不是由值确定的,而是由其内容的大小(例如文本)确定的。这样,我们在编写CSS时不知道.shad元素的宽度。 - Matthias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接