搞前端的朋友都晓得,平时切图摸鱼的时候,最多用到的就是 background-size: cover 把背景图撑满整个盒子,妥妥的省事。但有一天碰到个需求,要在鼠标划上去的时候让背景条纹像吃了摇头丸一样横向展开,光靠 cover 那点本事根本搞不定。这玩意儿到底咋弄?下面直接上硬核操作。
基础搭建
整个效果依赖 background-size 这个属性的二值语法,它能单独控制背景图片的宽和高。先整个最简单的 HTML 结构,一个 <div> 就够:
<div class="box"></div>.box {
width: 500px;
height: 500px;
background: palegreen;
}这里用 palegreen 只是临时打个底,后面会换掉。注意 background-size 如果只写一个值,第二个值默认是 auto,很容易让条纹叠成一坨。所以后续必须把高度也锁死。
条纹制作
要做出五条横向条纹,不能直接用 repeating-linear-gradient,因为每条条纹的宽度不一样,而且还要做过渡动画。换一种思路:用五个独立的 linear-gradient 堆叠在一起,每个渐变都是纯黑色到纯黑色,分别放在容器右上角的不同垂直偏移位置。
.box {
--gt: linear-gradient(black, black);
--n: 100px;
width: 500px;
height: 500px;
background:
var(--gt) top right,
var(--gt) top var(--n) right,
var(--gt) top calc(var(--n) * 2) right,
var(--gt) top calc(var(--n) * 3) right,
var(--gt) top calc(var(--n) * 4) right,
palegreen;
background-repeat: no-repeat;
}这里有个容易翻车的地方:如果不写 background-repeat: no-repeat,那些背景图会默认平铺,整个画面直接黑成煤球。每个黑色渐变块现在还没有尺寸,看起来就是一块实心黑。接下来用 background-size 给每个条纹单独设置宽度和高度:
.box {
/* 接上面代码 */
background-size: 60% var(--n), 90% var(--n), 70% var(--n), 40% var(--n), 10% var(--n);
}这样每条条纹的高度都是 100px,宽度分别是容器宽度的 60%、90%、70%、40%、10%。如果希望条纹之间留出空隙,把高度稍微缩小一点就行:
.box {
--h: calc(var(--n) - 5px);
background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
}减掉 5px 之后,每条条纹下方就会露出一小截底色,变成间隙效果。
混合模式
光有黑白条纹还不够,最终要上真正的彩色渐变。这里用两层 <div> 叠罗汉,外层父容器用 Grid 把它们重合在一起:
<section class="stripes-wrapper">
<div class="gradient-layer"></div>
<div class="mask-layer"></div>
</section>.stripes-wrapper {
display: grid;
align-items: center;
justify-items: center;
width: 500px;
height: 500px;
}
.stripes-wrapper > div {
width: inherit;
height: inherit;
grid-area: 1 / 1;
}第一层放真正的渐变色,比如从左到右的红橙渐变:
.gradient-layer {
background: linear-gradient(to right, red, orange);
}第二层放之前做好的黑白条纹,背景底色换成白色:
.mask-layer {
--gt: linear-gradient(black, black);
--n: 100px;
--h: calc(var(--n) - 5px);
background:
var(--gt) top right,
var(--gt) top var(--n) right,
var(--gt) top calc(var(--n) * 2) right,
var(--gt) top calc(var(--n) * 3) right,
var(--gt) top calc(var(--n) * 4) right,
white;
background-repeat: no-repeat;
background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
mix-blend-mode: screen;
}mix-blend-mode: screen 这个属性很关键:黑色区域会让底下的渐变漏出来,白色区域保持白色。最终呈现出来就是彩色条纹叠在白色底上。如果底色不是纯白,比如带一点米黄,那么整个背景会透出那种奶油质感。
悬停动画
鼠标划过外层容器时,让所有条纹的宽度瞬间变成 100%,并且加上平滑过渡。选中第二层 .mask-layer 来改:
.stripes-wrapper:hover > .mask-layer {
background-size: 100% var(--h);
transition: background-size 1s;
}这样每条条纹就会像拉面一样从左边弹到右边,宽度占满整个容器。注意 transition 只能作用在 background-size 上,其他属性比如颜色、位置都不会动。如果要让过渡更丝滑,可以给 .mask-layer 预先加上 transition: background-size 0.3s ease-out。
完整方案
下面是一份可以直接复制粘贴的成品代码,包含所有必要样式和一个简单的文字示例:
<section style="
display: grid;
align-items: center;
justify-items: center;
width: 500px;
height: 500px;
background: #faf0e6; /* 米色底 */
">
<div style="
width: inherit;
height: inherit;
grid-area: 1 / 1;
background: linear-gradient(135deg, #ff7e5e, #feb47b);
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
font-weight: bold;
color: white;
text-shadow: 0 0 5px black;
">
划我
</div>
<div style="
width: inherit;
height: inherit;
grid-area: 1 / 1;
--gt: linear-gradient(black, black);
--n: 100px;
--h: calc(var(--n) - 5px);
background:
var(--gt) top right,
var(--gt) top var(--n) right,
var(--gt) top calc(var(--n) * 2) right,
var(--gt) top calc(var(--n) * 3) right,
var(--gt) top calc(var(--n) * 4) right,
white;
background-repeat: no-repeat;
background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
mix-blend-mode: screen;
transition: background-size 0.8s cubic-bezier(0.2, 0.9, 0.4, 1.1);
"></div>
</section>
<style>
section:hover > div:last-child {
background-size: 100% var(--h);
}
</style>把上面这段丢进任意 HTML 文件里,鼠标划上去就能看到条纹像扯桌布一样铺满整个盒子。如果要调整条纹数量、方向或者颜色,只需要改 --n 的值(控制间距)和第一层的 linear-gradient 参数。水平条纹变垂直条纹?把所有 top right 换成 left top,然后把宽度值改成高度值即可。
