悬停时过渡的动画背景条纹

Avatar of Preethi
Preethi on

DigitalOcean 为您的旅程的每个阶段提供云产品。立即开始使用 $200 免费积分!

您多久使用一次 CSS background-size 属性?如果您像我一样 - 以及可能很多其他前端人员 - 那么通常是当您 background-size: cover 一张图像以填充整个元素的空间时。

好吧,我遇到了一个有趣的挑战,它需要更高级的背景大小:悬停时过渡的背景条纹。看看这个,然后用鼠标悬停在上面

那里发生的事情远不止背景的大小,但这正是我让条纹过渡所需的技巧。我想向您展示我是如何到达那里的,不仅因为我认为这是一个非常不错的视觉效果,而且因为它要求我对渐变和混合模式进行创造性的处理,我认为您可能会喜欢。

让我们从一个非常基本的设置开始,以保持简单。我说的是 HTML 中的一个 <div>,它被设计为一个绿色正方形

<div></div>
div {
  width: 500px;
  height: 500px;
  background: palegreen;
}
Perfect square with a pale green background color.

设置背景条纹

如果您看到这些条纹时直接想到的是 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 简写中设置 background-repeat,但我决定在这里将其分解出来以保持易于阅读。

偏移条纹

我们实际上有条纹,但很难分辨,因为它们之间没有间隔,并且它们覆盖了整个容器。更像是我们有一个纯黑色的正方形。

这就是我们使用 background-size 属性的地方。我们要设置条纹的高度和宽度,并且该属性支持双值语法,它允许我们精确地做到这一点。而且,我们可以通过用逗号分隔它们的方式来链接这些大小,就像我们在 background 上所做的那样。

让我们从简单地先设置宽度开始。对 background-size 使用单值语法会设置宽度并将高度默认为 auto。我在这里使用完全任意的值,因此将值设置为最适合您设计的那些值

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: 60%, 90%, 70%, 40%, 10%;
}

如果您使用的是我使用的相同的值,您将得到以下结果

看起来我们没有为所有条纹设置宽度,对吧?那是因为单值语法的 auto 高度行为。第二条纹比它下面的其他条纹更宽,并且它覆盖了它们。我们应该设置高度,这样我们才能看到我们的工作。它们的高度应该都相同,我们实际上可以再次使用 --n 变量,以保持简单

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: 60% var(--n), 90% var(--n), 70% var(--n), 40% var(--n), 10% var(--n); // HIGHLIGHT 15
}

啊,好多了!

在条纹之间添加间隙

如果您的设计不需要条纹之间的间隙,那么这完全是一个可选步骤,但我的设计需要,而且它并不复杂。我们稍微更改每个条纹的 background-size 的高度,减少该值,以便它们无法完全填充垂直空间。

我们可以继续使用我们的 --n 变量,但使用 calc() 减去一个小的值,比如 5px,以获得我们想要的结果。

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);

我们可以使用另一个变量来消除大量重复

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

蒙版和混合

现在,让我们将到目前为止出于视觉目的而使用的 palegreen 背景颜色替换为白色。

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. */
}

这种黑白图案非常适合蒙版和混合。为此,我们首先要将我们的 <div> 包裹在一个新的父容器中,并在其下方引入一个第二个 <div>

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

我们在这里将进行一些 CSS 重构。现在我们有了新的父容器,我们可以将我们对 <div> 使用的固定 widthheight 属性传递到那里

section {
  width: 500px;
  height: 500px;
} 

我还要使用 CSS Grid 将两个 <div> 元素彼此叠放。这与 Temani Afif 用于创建他的 超级酷的图片库 的技巧相同。我们的想法是,我们将两个 div 使用 grid-area 属性放置在整个容器之上,并将所有内容对齐到中心

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

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

现在,看看这个。我之前使用从黑色到黑色的纯色渐变的原因是为了让我们能够蒙版和混合这两个 <div> 层。这与我们调用 mask 属性时的真正蒙版意义不同,但层之间的对比控制着哪些颜色可见。被白色覆盖的区域将保持白色,被黑色覆盖的区域会泄漏。 MDN 关于混合模式的文档 对此工作原理有很好的解释。

为了使其生效,我将在第一个 <div> 上应用我们想要看到的真实渐变,同时在新的 <div> 上应用我们初始 <div> 的样式规则,使用 :nth-child() 伪选择器

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>)被悬停时发生这种情况。当它被悬停时,我们将更改包含在第二个 <div> 中的条纹的背景大小

/* When <section> is hovered, change the second div's styles */
section:hover > div:nth-child(2){
  /* styles go here */
}

我们将需要将条纹的 background-size 更改为容器的整个宽度,同时保持相同的高度

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

这将“快速”将背景扩展到整个宽度。如果我们在此基础上添加一点 transition,那么我们将看到条纹在悬停时扩展

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

这是那个最终的演示,再次

我只是在那里添加了文本以显示在不同上下文中使用它可能是什么样子。如果您也这样做,那么确保文本颜色和渐变中使用的颜色之间有足够的对比度,以符合 WCAG 指南。当我们简要谈及可访问性时,值得 考虑用户对减少运动的偏好,当涉及到悬停效果时。

总结!

很不错,对吧?我当然这么认为。我喜欢的另一件事是它很容易维护和定制。例如,我们可以通过更改几个值来更改条纹的高度、颜色和方向。您甚至可以将其中的一些内容——比如颜色和宽度——变量化,使其更具可配置性。

我真的很想知道您是否会以不同的方式处理这个问题。如果是,请在评论中分享!看看我们可以收集多少个变体会很酷。