很多前端老铁在切页面时,都碰到过这种需求:想让背景条纹在鼠标悬停时平滑变宽,但又不想用图片或者SVG。纯CSS能不能实现?当然能,核心就是background-size配合混合模式。下面直接上一套能跑通、能改、能复用的完整流程。
搞背景条纹悬停动画,光设背景图可不行。关键是理解
background-size支持双值控制宽高,配合linear-gradient生成纯色块,再用mix-blend-mode: screen让下层渐变色透出来。整个过程不用额外图片,通过background-position错开条纹位置,悬停时把background-size宽度改到100%加过渡动画,就能丝滑扩展。注意控制好间隙和重复平铺,避免条纹堆叠。
background-size双值用法
background-size平时用cover或contain比较多,但它的双值语法才是做条纹动画的法宝。第一个值控制宽度,第二个值控制高度。比如background-size: 60% 100px表示背景图片占容器宽度的60%,高度固定100像素。如果只写一个值,第二个默认auto,高度会按比例缩放,容易翻车。
制作五条错位横条纹
先把容器架子搭起来。用一个<section>当父层,里面塞两个<div>,后面用来做混合叠加。
<section class="stripe-stage">
<div class="stripe-bg"></div>
<div class="stripe-mask"></div>
</section>.stripe-stage {
width: 500px;
height: 500px;
display: grid;
align-items: center;
justify-items: center;
}
.stripe-stage > div {
width: inherit;
height: inherit;
grid-area: 1 / 1;
}父级固定宽高,用网格让两个子元素重叠在同一块区域。接下来做条纹层。目标是五条黑色横条,从上往下每隔100像素放一条。用linear-gradient(black, black)生成纯黑块——这里没有渐变,就是从黑到黑,看起来就是个实心方块。然后用background-position把每条分别钉到不同的垂直位置。
.stripe-mask {
--stripe-solid: linear-gradient(black, black);
--offset: 100px;
background:
var(--stripe-solid) top right,
var(--stripe-solid) top var(--offset) right,
var(--stripe-solid) top calc(var(--offset) * 2) right,
var(--stripe-solid) top calc(var(--offset) * 3) right,
var(--stripe-solid) top calc(var(--offset) * 4) right,
white;
background-repeat: no-repeat;
}注意这里背景色设成了白色,底层叠了五条黑色条纹。background-repeat: no-repeat必须加上,不然条纹会重复平铺满整个容器,变成一坨黑。
控制条纹宽高和间隙
光有位置还不够,每条条纹的宽高得单独设置。用background-size分别指定每条的黑块尺寸。宽度用百分比(不同条纹不一样宽),高度统一用--offset减掉5像素,这样每条下方会留出5像素空隙。
.stripe-mask {
/* ... 上面代码不变 ... */
--gap: calc(var(--offset) - 5px);
background-size: 60% var(--gap), 90% var(--gap), 70% var(--gap), 40% var(--gap), 10% var(--gap);
}这时候看效果,应该能看到五条不同宽度的黑色横条,从上往下排列,每条之间有5像素的白色缝隙。如果条纹没有显示全,检查一下background-position里面的top right是否写对——right让条纹靠右对齐,避免偏移出视野。
混合模式让颜色透出来
把上面.stripe-mask的背景颜色从白色换成白色(本来就是白色),然后把真正想展示的渐变色放到第一个<div>上。
.stripe-bg {
background: linear-gradient(to right, red, orange);
}现在两个div叠在一起,下层是红橙渐变,上层是黑条加白底的图案。要想让下层渐变只从黑色区域透出来,白色区域保持白色,需要用mix-blend-mode: screen。
.stripe-mask {
mix-blend-mode: screen;
}screen混合模式会把黑色部分变透明,白色保持不变。这样一来,红橙渐变就从黑色条纹的位置露出来了,白色背景区域还是白色。如果希望背景色稍微暗一点(比如米色),把.stripe-mask的白色背景改成#f5f0e6,透出的颜色会更柔和。
| 混合模式 | 效果描述 |
|---|---|
| screen | 黑色消失 |
| multiply | 白色消失 |
| overlay | 对比增强 |
悬停扩展动画
最后加悬停效果:鼠标放到父容器上时,所有条纹的宽度变成100%,并且带过渡动画。
.stripe-stage:hover > .stripe-mask {
background-size: 100% var(--gap), 100% var(--gap), 100% var(--gap), 100% var(--gap), 100% var(--gap);
transition: background-size 1s ease;
}注意这里background-size的多个值必须全部改成100%,数量要对齐。如果只改第一个,其他条纹不会动。过渡动画加在.stripe-mask本身上也行,但为了性能,直接加在悬停状态里。
整个流程跑下来,悬停时条纹从左向右(或从右向左,取决于之前设的right位置)平滑展开。如果想改方向,把background-position里的right换成left,条纹就会从左边缘伸出来。
有强迫症的小伙伴可能发现,background-size过渡在部分浏览器上会有点卡顿,尤其是多个背景层同时动画的时候。可以加will-change: background-size稍微优化一下,不过大部分现代浏览器已经处理得很丝滑了。
