likes
comments
collection
share

css利用background-size实现悬停动画

作者站长头像
站长
· 阅读数 10

您多久访问一次 CSSbackground-size属性?可能还有很多同学,通常是利用background-size: cover来进行背景图像填充。其实background-size属性在做背景悬停动画非常方便,下面我们来拆解一个例子:

该案例除了背景大小的改变,还有运用了渐变、混合的css技巧,我个人觉得这是个比较好的视觉交互效果。所有看似复杂的效果,其实都是一些简单的事情堆叠而成的。下面我们就来一一讲解,首先我们从一个万能的绿色方块说起:

    div {
      width: 500px;
      height: 500px;
      background: palegreen;
    }

设置背景条纹

如果您在看到这些条纹时直接想到 CSS 线性渐变,那么我们已经在同一思路上了。在这种情况下,我们不能完全重复渐变,因为我们希望条纹占据不均匀的空间量并对其进行过渡,但我们可以通过将五个背景链接到现有背景颜色之上并将它们放在顶部来创建五个条纹-容器右侧:

    div {
      width: 500px;
      height: 500px;
      background: 
        linear-gradient(black, black) top right,
        linear-gradient(black, black) top 100px right,
        linear-gradient(black, black) top 200px right,
        linear-gradient(black, black) top 300px right,
        linear-gradient(black, black) top 400px right, 
        palegreen;
    }

我做了水平条纹,另外,我们可以使用自定义属性来简化这一过程:

    div {
      --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;
    }

上述样式自定义变量中,--gt表示梯度,--n是我们用来向下推动条纹的常量。你可能已经注意到我没有设置真正的渐变,而是在linear-gradient()函数中设置了纯黑色条纹,这是有意为之的,稍后我们会解释为什么要这样做。

在继续之前我们应该做的另一件事是防止我们的背景重复;否则,它们将平铺并填满整个空间:

    div {
      --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-size属性了,该属性支持双值语法,能够满足我们设置条纹的高度和宽度。而且,我们可以用逗号分隔这些尺寸,就像我们在background中设置多组渐变一样。

让我们先从设置宽度开始。使用单值语法background-size设置宽度并将高度默认为auto. 我在这里使用了完全任意的值:

这效果看起来不像我们为所有条纹设置了宽度,因为auto单值语法的高度行为,第二条条纹比它下面的其他条纹宽,并且覆盖了它们。因此,我们应该设置高度,以便我们可以看到我们的效果。它们应该都是相同的高度,我们可以再次使用我们的--n变量,以保持简洁代码:

在条纹之间添加间隙

条纹之间的间隙,我们可以稍微减小每个条纹的高度background-size值,以便使它们无法填满整个垂直空间即可。假如中间需要5像素的间隙,我们的代码可以这样写:

    background-size: 60% calc(var(--n) - 5px), 90% calc(var(--n) - 5px), 70% calc(var(--n) - 5px), 40% calc(var(--n) - 5px), 10% calc(var(--n) - 5px);

我们可以使用css变量来减去多余重复的工作:

    div {
      --h: calc(var(--n) - 5px);
      /* etc. */
      background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
    }

混合模式

绿了那么久,让我们把背景切换回白色:

    div {
      /* etc. */
      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, 
        #fff;
      /* etc. */
    }

像这样的黑白图案非常适合遮蔽和混合。为此,我们可以引入一个新的父容器来承接将要混合的元素:

    <section> 
        <div></div>
        <div></div>
    </section>

我们将在这里做一些 CSS 重构。现在我们有了一个新的父容器,我们可以传递我们在那边使用的固定宽、高,并使用 CSS Grid 将这两个<div>元素放在彼此之上:

    section {
      display: grid;
      align-items: center;
      justify-items: center;
      width: 500px;
      height: 500px;
    } 

    section > div {
      width: inherit;
      height: inherit;
      grid-area: 1 / 1;
    }

为了达到效果,我们给第一个div设置好我们想要看到的渐变颜色效果,给第二个div来设置到时候需要混合、遮罩的样式:

    div:nth-child(1) { 
      background: linear-gradient(to right, red, orange); 
    }

    div:nth-child(2)  {
      --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);
    }

到这里,实际上我们将看不到与引入新容器之前有什么视觉差异。因为我们只是做了样式的堆叠,并还没有完成实际的混合。我们可以使用screen混合模式来现实我们想要的效果(关于混合模式,大家可以自行了解)

    div:nth-child(2)  {
      /* etc. */
      mix-blend-mode: screen;
    }

在本文开头演示中使用了米色背景色,这种稍微深一点的灰白色可以让一点颜色渗透到背景的其余部分:

悬停效果

到目前为止,想要获得悬停效果,我们只需要保持背景条纹的高度不变,改变其宽度即可:

    section:hover > div:nth-child(2){
      background-size: 100% var(--h);
      transition: background-size 1s;
    }

文中案例分解基本完了😘下班,周末愉快!