在 CSS 中重现 Apple Music 热门歌曲播放列表动画

Avatar of Geoff Graham
Geoff Graham

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

Apple Music 具有“空间音频”功能,其中您耳机中的音乐方向取决于设备的位置。 很难解释它到底有多棒。 但这不是我要谈论的。

我打开了 Apple Music 应用程序,看到了一个支持空间音频的热门歌曲特色播放列表。 它的封面是一个明亮的粉色容器,里面装着一堆一个叠一个的盒子。 这些盒子一次动画一个,在容器的中心淡入,然后在缩放至容器大小的同时淡出。 像一个无限循环。

Animated GIF showing the Apple Music UI we are recreating. It's brightly colored shades of pink against a dark gray background with information about the playlist to the right of the pattern, and options to play and shuffle the sings in orange buttons.

酷! 我知道我必须在 CSS 中重新创建它。 所以我做了。

它是这样工作的……

标记

我从 HTML 开始。 显然,我们需要定义一个容器,再加上我们要动画的任何数量的框。 我在容器中使用了 10 个框。

<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <!-- etc. -->
</div>

对于 HTML,就这些了。 我们可以直接跳到 CSS!

样式容器

这里没什么花哨的。 我根据我在 Apple Music 中看到的测量了近似尺寸,恰好是 315px × 385px。 然后我截取了封面的屏幕截图,并将其放到我的图像编辑应用程序中以获得最浅的可能颜色,它位于容器的外部边缘。 我的颜色选择器停在了 #eb5bec 上。

.container {
  background-color: #eb5bec;
  height: 315px;
  width: 385px;
}

在做这件事的时候,我知道我可能希望它成为一个网格容器,以便将框和任何其他元素对齐到中心。 我还认为盒子本身将从容器的中心开始,并且一个叠在一个上面,这意味着将进行一些绝对定位。 这也意味着容器应该具有相对定位以控制它们。

.container {
  background-color: #eb5bec;
  height: 315px;
  position: relative;
  width: 385px;
}

并且由于我们希望框从中心开始,我们可以使用网格来帮助实现这一点

.container {
  background-color: #eb5bec;
  display: grid;
  height: 315px;
  place-items: center;
  position: relative;
  width: 385px;
}

如果容器中的框向外增长,那么它们可能会扩展到容器之外。 最好隐藏任何可能的溢出。

.container {
  background-color: #eb5bec;
  height: 315px;
  overflow: hidden;
  position: relative;
  width: 385px;
}

我还注意到它有一些圆角,所以让我们在添加它的时候添加进去。

.container {
  background-color: #eb5bec;
  border-radius: 16px;
  height: 315px;
  position: relative;
  width: 385px;
}

到目前为止,一切都好!

样式框

我们在标记中拥有 10 个 .box 元素,我们希望它们一个叠在一个上面。 我从一些绝对定位开始,然后将它们的大小设置为 100px 方形。 然后我使用我的图像编辑应用程序做了同样的事情来找到框的最暗颜色值,它是 #471e45

.box {
  background: #471e45;
  height: 100px;
  position: absolute;
  width: 100px;
}

当框变大时,它们似乎会淡出。 这允许一个框透过另一个框看到,所以让我们一开始将它们设置为不透明。

.box {
  background: #471e45;
  height: 100px;
  opacity: 0.5;
  position: absolute;
  width: 100px;
}

酷,酷。 我们无法看到所有叠在一起的框,但我们正在取得进展!

创建动画

准备好编写一些 @keyframe 吗? 我们将使它非常简单,从 0 到 100% 不包含任何中间步骤。 我们甚至不需要那些百分比!

@keyframes grow {
  from {
    /* do stuff */
  }
  to {
    /* do stuff */
  }
}

具体来说,我们希望从开始到结束发生两件事

  • 框从我们的起始不透明度值 0.5 变为 0(完全透明)。
  • 框向上缩放至容器边缘。
@keyframes grow {
  from {
    opacity: 0.5;
    transform: scale(0);
  }
  to {
    opacity: 0;
    transform: scale(3.85);
  }
}

我如何将框向上缩放 3.85? 我们的框是 100px 方形,容器是 385px 高。 值 3.85 使框在完全淡出时达到 385px,当我们到达那里时,这将使动画变得平滑线性。

说到这里……

应用动画

在我们的框上调用动画非常容易。 只需确保它以无限的方式在一条线性计时函数上移动,这样它就像 Energizer Bunny 一样,不断地前进前进前进前进……

.box {
  animation: grow 10s linear infinite; /* 10s = 10 boxes */
  /* etc. */
}

这给了我们想要的动画。 但是! 所有框都在同一时间移动,因此我们只看到一个巨大的框在增长。

我们必须错开那些小家伙。 不幸的是,普通 CSS 中没有循环,因此我们必须分别延迟每个框。 我们可以从设置延迟的自定义属性开始,将其设置为一秒,然后在每个实例上重新定义自定义属性。

.box {
  --delay: 1s;
  
  animation-delay: var(--delay);
  /* same as before */
}
.box:nth-child(2) {
  --delay: 2s;
}
.box:nth-child(3) {
  --delay: 3s;
}
.box:nth-child(4) {
  --delay: 4s;
}
.box:nth-child(5) {
  --delay: 5s;
}
/* five more times... */

太棒了!

继续摇摆

就这些了! 我们刚刚重新创建了 Apple Music 使用的相同效果。 我们可以添加一些收尾工作,比如内容等等。 这是我的最终版本