单元素加载器:点

Avatar of Temani Afif
Temani Afif

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

在本系列文章中,我们将探讨加载器。更重要的是,我们将分解一些常见的加载器模式,以及如何仅使用一个 div 元素来重新创建它们。到目前为止,我们已经分析了 经典的旋转加载器。现在,让我们看看另一个您可能已经很熟悉的加载器:**点**。

点加载器无处不在。它们很简洁,因为它们通常由三个点组成,看起来有点像文本省略号(...),它们在周围跳动。

文章系列

我们的目标是使用一个单一的 div 元素来实现相同的效果。换句话说,每个点没有一个 div,也不需要对每个点进行单独的动画。

上面那个加载器示例使用一个 div 元素、几个 CSS 声明以及没有伪元素创建。我正在结合使用 CSS 的 backgroundmask 技术。完成之后,我们将看到如何通过动画化背景渐变来营造每个点在依次上下移动时改变颜色的错觉。

背景动画

让我们从背景动画开始

.loader {
  width: 180px; /* this controls the size */
  aspect-ratio: 8/5; /* maintain the scale */
  background: 
    conic-gradient(red   50%, blue   0) no-repeat, /* top colors */
    conic-gradient(green 50%, purple 0) no-repeat; /* bottom colors */
  background-size: 200% 50%; 
  animation: back 4s infinite linear; /* applies the animation */
}

/* define the animation */
@keyframes back {
  0%,                       /* X   Y , X     Y */
  100% { background-position: 0%   0%, 0%   100%; }
  25%  { background-position: 100% 0%, 0%   100%; }
  50%  { background-position: 100% 0%, 100% 100%; }
  75%  { background-position: 0%   0%, 100% 100%; }
}

我希望这看起来很简单。我们拥有一个宽度为 180px.loader 元素,它显示了两个圆锥渐变,每个渐变在两种颜色之间都有硬色停顿 — 第一个渐变是 .loader 上半部的红色和蓝色,第二个渐变是下半部的绿色和紫色。

由于加载器背景的大小 (200% 宽度),我们一次只能在每个半部分看到一种颜色。然后,我们有一个小小的动画,它会不断地将这些背景渐变的位置向左、向右以及反向移动。

在处理背景属性(尤其是 background-position)时,我总是参考我的 Stack Overflow 答案,其中我详细解释了所有内容的工作原理。如果您不熟悉 CSS 背景技巧,我强烈建议阅读该答案以帮助您了解接下来要做什么。

在动画中,请注意第一层是 Y=0%(位于顶部)而 X0% 变化到 100%。对于第二层,我们对 X 做同样的事情,但 Y=100%(位于底部)。

为什么使用 conic-gradient() 而不是 linear-gradient()

好问题!直观地,我们应该使用线性渐变来创建这样的双色渐变

linear-gradient(90deg, red 50%, blue 0)

但我们也可以使用 conic-gradient() 来实现相同的目的 — 并且代码更少。我们减少了代码量,同时也学习了一个新的技巧!

将颜色左右滑动是让它看起来像我们在改变颜色的好方法,但如果我们可以立即改变颜色,那就更好了 — 这样,加载器点就不会同时闪烁两种颜色。为此,让我们将 animation 的计时函数从 linear 更改为 steps(1)

加载器点

如果您已经完成了本系列文章中的 第一篇文章,我敢肯定您知道接下来要做什么:**CSS 蒙版!** 蒙版如此棒的原因是它们让我们可以 “剪切”另一个元素形状的背景。因此,在这种情况下,我们想要制作几个点,让背景渐变穿过这些点,并剪切掉背景中不是点的一部分的任何部分。

我们将为此使用 radial-gradient()

.loader {
  width: 180px;
  aspect-ratio: 8/5;
  mask:
    radial-gradient(#000 68%, #0000 71%) no-repeat,
    radial-gradient(#000 68%, #0000 71%) no-repeat,
    radial-gradient(#000 68%, #0000 71%) no-repeat;
  mask-size: 25% 40%; /* the size of our dots */
}

那里有一些重复的代码,所以让我们创建一个 CSS 变量来简化代码

.loader {
  width: 180px;
  aspect-ratio: 8/5;
  --_g: radial-gradient(#000 68%, #0000 71%) no-repeat;
  mask: var(--_g),var(--_g),var(--_g);
  mask-size: 25% 40%;
}

酷酷的。但现在我们需要一个新的动画来帮助点在动画渐变之间上下移动。

.loader {
  /* same as before */
  animation: load 2s infinite;
}

@keyframes load {      /* X  Y,     X   Y,    X   Y */
  0%     { mask-position: 0% 0%  , 50% 0%  , 100% 0%; } /* all of them at the top */
  16.67% { mask-position: 0% 100%, 50% 0%  , 100% 0%; }
  33.33% { mask-position: 0% 100%, 50% 100%, 100% 0%; }
  50%    { mask-position: 0% 100%, 50% 100%, 100% 100%; } /* all of them at the bottom */
  66.67% { mask-position: 0% 0%  , 50% 100%, 100% 100%; }
  83.33% { mask-position: 0% 0%  , 50% 0%  , 100% 100%; }
  100%   { mask-position: 0% 0%  , 50% 0%  , 100% 0%; } /* all of them at the top */
}

是的,那里总共有三个径向渐变,它们都具有相同的配置和相同的大小 — 动画将更新每个渐变的位置。请注意,每个点的 X 坐标都是固定的。mask-position 的定义使得第一个点位于左侧 (0%),第二个点位于中心 (50%),第三个点位于右侧 (100%)。我们只更新 Y 坐标,从 0%100%,以使点跳动。

Dot loader dots with labels showing their changing positions.

这就是我们得到的结果

现在,将它与我们的渐变动画结合起来,魔法就开始发生了

点加载器变体

我们在上一个示例中创建的 CSS 变量使得交换新的颜色并创建更多相同加载器的变体变得更加容易。例如,不同的颜色和大小

我们的点还有什么其他的移动方式吗?

在这里,我所做的只是更新了动画以考虑不同的位置,我们得到了另一个使用相同代码结构的加载器!

我用于蒙版层的动画技术也可以用于背景层,以创建一个颜色相同的许多不同的加载器。 我写了一篇关于这方面的详细文章。 您会发现,从相同的代码结构中,我们只需更改几个值,就可以创建不同的变体。我在文章末尾分享了一些示例。

为什么不是一个带有一个点的加载器?

这个应该很容易理解,因为我使用了相同的技术,但逻辑更简单

这是另一个加载器示例,我还在其中对 radial-gradient 进行动画处理,并结合了 CSS 滤镜mix-blend-mode 来创建模糊效果

如果您查看代码,您会发现我真正做的只是对 background-position 进行动画处理,就像我们在之前的加载器中所做的那样,但添加了一点 background-size 来让它看起来像是 blob 在吸收点时变大了。

如果您想了解这种模糊效果背后的魔法,可以参考 这些交互式幻灯片(仅限 Chrome)由 Ana Tudor 创建,因为她对该主题的讲解非常透彻!

这是另一个点加载器想法,这次使用不同的技术

这个示例只有 10 个 CSS 声明和一个关键帧。主元素及其两个伪元素具有相同的背景配置,只有一个径向渐变。每个元素创建一个点,总共三个。动画通过使用每个点不同的延迟将渐变从上到下移动。

哦,还要注意这个演示如何使用 CSS Grid。这使得我们可以利用网格的默认 stretch 对齐,这样两个伪元素都将覆盖其父元素的整个区域。无需调整大小!使用 translate() 将它们稍微移动一下,我们就完成了。

更多示例!

为了强调这一点,我想给您留下一些额外的示例,它们实际上是我们已经看过的示例的变体。当您查看演示时,您会发现我们在这里介绍的方法非常灵活,可以打开许多设计可能性。

接下来…

好的,我们在本文中介绍了 点加载器,在上一篇文章中介绍了 旋转器。在本系列文章的下一篇文章中,我们将把注意力转向另一种常见的加载器类型:**条**。我们将借鉴之前学到的许多知识,看看如何扩展它们来创建一个另一个仅使用少量代码并尽可能灵活的单元素加载器。

文章系列