网页上模仿钱包卡片露出一截的缝隙效果,CSS咋整才自然?

2,917字
12–19 分钟
in

这个效果就像是文件夹里塞了张纸,纸边儿露出一小截;又或者钱包里插着信用卡,卡片冒个尖儿出来方便瞅一眼是哪张卡。在CSS里,这玩意儿叫“slit”(缝隙效果)。说白了,就是制造一个假开口,让底下的元素从开口处探出个头来,看着贼自然。

目录

缝隙效果靠两个东西配合:一个假阴影(不是box-shadow那种),一个遮挡层。阴影用模糊的渐变矩形做出立体感,遮挡层盖住阴影的一半,再往左一挪,视觉上就形成了开口。整个过程可以用Grid或Flexbox来堆叠元素,代码不复杂,但细节拿捏到位才像那么回事儿。

阴影咋造

一般新手可能直接甩个box-shadow完事,但那玩意儿太死板。真正能动态适配、还能做动画的阴影,得自己动手搓出来。

搞一个细长竖条矩形,背景弄成渐变:中间深、两边浅。然后给它加一层blur()滤镜,模糊后中间区域自然就暗下去,边缘过渡柔和,看起来就像真实的缝隙暗影。

<div class="slit-shadow"></div>
.slit-shadow {
  width: 60px;
  height: 100%;
  background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.6) 50%, rgba(0,0,0,0) 100%);
  filter: blur(8px);
}

实际操作时,这个阴影的宽度得看具体设计,一般20-80px就够。blur()值太大阴影会糊成一团,太小又显得生硬,建议从6px开始调。而且这个阴影元素必须单独占一层,方便后面被遮盖。

遮盖设计

遮盖就是盖住阴影左边那一半的矩形,颜色必须跟整个容器的背景色一模一样。比如页面背景是#f5f5f5,那遮盖背景也得是#f5f5f5,这样盖上去才像是一体。

<div class="slit-cover"></div>
.slit-cover {
  width: 50%;
  height: 100%;
  background: inherit; /* 继承父级背景色,省事 */
}

这里有个坑:background: inherit得保证父元素背景是纯色且显式定义过。如果父级背景是图片或者渐变,那遮盖就得用mask或者backdrop-filter来抠,操作更骚但原理一样。

叠放对齐

三个东西要叠在一块:最底下是真正的图片或内容,中间是阴影,最上面是遮盖。用CSS Grid一把梭,把所有子元素塞到同一个网格单元格里。

<main>
  <img src="card.jpg" alt="卡片图片">
  <div class="slit-shadow"></div>
  <div class="slit-cover"></div>
</main>
main {
  display: grid;
  place-items: center;
  background: #fff; /* 背景色,遮盖会继承这个 */
}
main > * {
  grid-area: 1 / 1; /* 全部堆在同一个格子 */
}

现在所有元素完全重叠。接下来把遮盖往左平移,露出底下阴影和图片的一部分。

.slit-cover {
  width: 50%;
  transform: translateX(calc(-50% - 25px));
}

这里25px就是阴影宽度的一半,平移量要刚好让阴影边缘露出来。平移太多会露出遮盖的边界穿帮,太少阴影不明显。建议用calc(-50% - 阴影宽度的一半)这个公式。

图片露头

图片或者其他要“露一截”的内容,本身就在最底层,不用额外处理。但是为了让露出的部分正好在缝隙中间,可以微调图片的位置,或者给阴影换个方向。

比如想让卡片从右边露出来,那就把阴影放到右侧,遮盖也改成从右边盖过来。代码稍微改改:

.slit-cover--right {
  width: 50%;
  transform: translateX(calc(50% + 25px));
}
.slit-shadow--right {
  /* 阴影放在右侧 */
  margin-left: auto;
}

这波操作直接拿捏了缝隙效果的核心:阴影+遮盖+偏移,三件套缺一不可。

另一种路子:Flexbox平替

Grid能叠元素,Flexbox也能凑合干,不过得用负margin或者绝对定位。更直接的法子是直接用position: relativeposition: absolute

<div style="position: relative; background: #fff;">
  <img src="card.jpg" style="display: block;">
  <div class="shadow" style="position: absolute; top:0; left:0; width:60px; height:100%; ..."></div>
  <div class="cover" style="position: absolute; top:0; left:0; width:50%; height:100%; background: inherit; transform: translateX(calc(-50% - 25px));"></div>
</div>

绝对定位的坑在于父级必须有position: relative,而且阴影和遮盖的层级得用z-index手动调。哪个在上哪个在下?遮盖必须比阴影高,阴影比图片高。

方案优点缺点
Grid叠层代码干净,不用管层级需要理解grid-area
绝对定位兼容性拉满z-index容易乱

玩出花活:曲线阴影和彩色缝隙

上面那个是直来直去的缝隙,要是想整个弯的阴影,比如像翻开书页那种弧线,可以把阴影的背景渐变改成径向渐变,或者用clip-path切个弧形。

.slit-shadow-curve {
  background: radial-gradient(ellipse at center, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0) 70%);
  filter: blur(12px);
  width: 80px;
}

遮盖也得跟着切弧形,不然直边盖弧边会露馅。用clip-path: polygon()或者border-radius都能整活。注意阴影和遮盖的形状必须完全匹配,不然穿帮就是分分钟的事。

还有个骚操作:不用单独元素做阴影,直接用::before伪元素造阴影,::after做遮盖。这样HTML结构更干净,但伪元素没法同时继承父级背景色,需要手动指定。

.slit-container::before {
  content: '';
  position: absolute;
  left: 0;
  width: 60px;
  height: 100%;
  background: linear-gradient(...);
  filter: blur(8px);
}
.slit-container::after {
  content: '';
  position: absolute;
  left: 0;
  width: 50%;
  height: 100%;
  background: #fff; /* 必须写死背景色 */
  transform: translateX(calc(-50% - 25px));
}

这种写法适合背景色固定不变的场景,如果背景是动态的或者主题可换,那还是用独立元素加background: inherit更稳。