发布于 2026-01-06 0 阅读
0

如何创建纯 CSS 插图并为其添加动画 - 第 2 部分 CSS 动画 DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

如何创建纯 CSS 插图并为其添加动画效果 - 第二部分

CSS动画

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

这是关于 CSS 插图和动画的三篇系列文章的第二篇。在这一篇中,我们将构建一个 CSS 宝丽来照片,然后学习如何为其添加动画效果。

第一部分:学习 CSS 笑脸的基础知识和工作流程技巧;
第二部分:CSS 宝丽来动画入门;
第三部分:CSS 灯塔场景的高级技巧。

我们将要建造的东西如下:

如果你想自己尝试搭建这个模型,请先暂停一下。这里的内容我们在上一部分已经介绍过了。不必过于纠结颜色和尺寸的精确度,记住,通常有多种方法可以达到相同的效果。

好的,我们开始吧。我们仔细观察这张图片,并对其进行分解。它由相当简单的形状组成,主要是圆角矩形和圆形,我们可以用基本的 CSS 轻松重现它们。让我们看看基本的 HTML 树状结构:

.polaroid
  .button
  .flash
  .polaroid-body
  .blinker
  .zoom
  .stripes
Enter fullscreen mode Exit fullscreen mode

.polaroid元素作为我们的主要容器,并将作为所有其他元素定位的参考。

我们先来为 html 和 body 选择器设置一些基本属性,以及一些颜色变量:

$background: #b5e8fb;
$grey: #34495e;
$dark-grey: #212f3d;

html, body { 
  height: 100%; 
  width: 100%; 
  padding:0;
  margin:0;
  overflow: hidden; 
} 
html { 
  box-sizing: border-box; 
} 
*, *:before, *:after { 
  box-sizing: inherit; 
}
body { 
  background: $background; 
} 
Enter fullscreen mode Exit fullscreen mode

我们插图中的所有元素都需要具有绝对定位,所有伪选择器也是:before如此:after

* { 
  position: absolute; 
}
*:before, *:after { 
  content: ""; 
  position: absolute; 
} 
Enter fullscreen mode Exit fullscreen mode

让我们将主容器在页面上垂直和水平居中,并为其指定宽度和高度。

.polaroid { 
  width: 420px;
  height: 280px;
  top: 50%; 
  left: 50%;
  transform: translate(-50%, -50%);
 }
Enter fullscreen mode Exit fullscreen mode

现在环境已经搭建完毕,我们可以开始制作拍立得相机的各种形状了。首先,我们需要一个.polaroid-body元素来代表相机的机身。我们可以使用 SASS 的 darken 函数来生成与背景相匹配的阴影。这样比使用纯黑色效果更柔和。

.polaroid-body {
  width: 100%;
  height: 100%;
  border-radius: 40px;
  background-color: #fff;
  box-shadow: 10px 10px darken($background, 5%);
}
Enter fullscreen mode Exit fullscreen mode

这个按钮很简单。我们想把它放在拍立得相机机身后面,HTML 的自然布局会自动帮我们实现这一点。

.button { 
  width: 10%; 
  height: 5%; 
  top: -2%; 
  left: 14%; 
  background-color: #cb214a; 
  border-radius: 16px; 
}
Enter fullscreen mode Exit fullscreen mode

由于我们需要两个闪光灯选择器,我们可以使用:after

 .flash { 
   width: 24%; 
   height: 15%;
   top: -12%; 
   left: 38%; 
   background-color: $grey; 
   border-radius: 8px; 
   &:after { 
     width: 36%; 
     height: 60%; 
     background-color: lighten($grey, 30%); 
     border-radius: 5px; 
     top: 10%; 
     left: 32%; 
   } 
}
Enter fullscreen mode Exit fullscreen mode

转向灯也很简单:

.blinker {
  width: 15px;
  height: 15px;
  border-radius: 15px;
  background-color: $dark-grey;
  top: 15%;
  left: 15%;
}
Enter fullscreen mode Exit fullscreen mode

接下来我们来看缩放功能:

.zoom { 
  width: 50%; 
  height: 75%;
  left: 25%; 
  top: 12.5%;
  background: $dark-grey; 
  border-radius: 50%; 
  border: 5px solid $grey; 
  box-shadow: 10px 10px rgba(0, 0, 0, 0.1); 
  overflow: hidden; 
  &:before { 
    width: 80%; 
    height: 80%; 
    top: 10%; 
    left: 10%; 
    border-radius: 50%; 
    background: #2c3e50; 
    border: 10px solid $grey; 
  } 
  &:after { 
    width: 40%; 
    height: 40%; 
    top: 30%; 
    left: 30%; 
    border-radius: 50%; 
    background: $dark-grey; 
  } 
}
Enter fullscreen mode Exit fullscreen mode

我们结合伪选择器和边框,仅用一个 div 就重现了缩放的不同部分。太棒了!

现在,我想为我们的缩放功能添加一些细节,但是伪类选择器用完了。让我们在 HTML 中添加一个 div 元素:

.polaroid
  .button
  .flash
  .polaroid-body
  .blinker
  .stripes
  .zoom
    .reflections
Enter fullscreen mode Exit fullscreen mode
.reflections { 
  background-color: #fff; 
  opacity: 0.3; 
  width: 100%; 
  height: 100%; 
  left: -35%; 
  top: -35%; 
  z-index: 99; 
  transform: rotate(-45deg); 
  &:after { 
    background-color: #fff; 
    width: 20px; 
    height: 20px; 
    border-radius: 50%; 
    left: 50%; 
    top: 105%; 
    opacity: 0.5; 
  } 
}
Enter fullscreen mode Exit fullscreen mode

主反射是由一个旋转了 45 度的正方形形成的。我给缩放元素添加了一个属性overflow:hidden,使其只显示与自身重叠的反射部分。:after我还使用伪类选择器添加了另一个较小的光反射。

我们的拍立得照片快完成了。我们需要添加最后一个细节:代表品牌的彩虹条纹。实现方法有很多种。最简单的方法是创建五个 div 元素,并分别设置不同的背景颜色。我们也可以像缩放功能那样,结合使用伪类选择器和边框。另一种方法是应用带有颜色断点的渐变。不过,我们将使用 box-shadow 属性并串联多个值。

.stripes {
  height: 7px;
  width: 50%;
  right: 0;
  top: 40%;
  box-shadow: 0px 7px rgb(214, 0, 121), 0px 14px rgb(230, 141, 21),
              0px 21px rgb(254, 200, 3), 0px 28px rgb(221, 229, 107),
          0px 35px rgb(62, 162, 48), 0px 42px rgb(1, 136, 194);
}
Enter fullscreen mode Exit fullscreen mode

这再次说明,实现同一目标通常有多种方法。没有绝对的对错之分,一切都取决于个人偏好。我喜欢尽可能保持代码简洁(DRY 原则),所以我通常会选择代码量最少的方法。

我们的拍立得照片拍完了!

CSS动画

现在到了我最喜欢的部分:制作插图动画!

在网页开发中,创建动画的方法有很多种,几乎所有方法都可以用来制作 CSS 图片动画。但是,为了契合本系列的主题,我们当然会使用 CSS 动画。

动画基础知识

CSS动画是通过两个步骤实现的。

假设你想创建一个旋转正方形的动画。

首先你需要一条@keyframes规则:

@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}
Enter fullscreen mode Exit fullscreen mode

这条规则由两个关键帧选择器组成,分别是 0% 和 100%,我们可以在它们之间添加 CSS 属性。这些属性将控制方块在动画该时刻的外观。

在上面的例子中,正方形将从 0 度旋转到 360 度。

这条规则中只定义了两个关键帧选择器,但我们可以根据需要添加任意数量。假设我们不希望正方形旋转一周,而是
旋转 180 度,然后再旋转回 0 度。这可以通过添加一个额外的关键帧选择器来实现:

@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  50% {
    transform: rotate(180deg)
  }
  100% {
    transform: rotate(0deg)
  }
}
Enter fullscreen mode Exit fullscreen mode

两个关键帧选择器之间的任何一点都代表从一个选择器到另一个选择器的过渡状态。例如,假设动画是线性的,那么在 25% 的位置,正方形将旋转 90 度。

第二步是在选择器中调用此规则,并指定动画属性:

.square {
  animation-name: rotation;
  animation-duration: 5s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
Enter fullscreen mode Exit fullscreen mode

或者使用快捷方式:

.square {   
  animation: rotation 5s linear infinite; 
}
Enter fullscreen mode Exit fullscreen mode

这些动画子属性允许我们调用@keyframes规则并设置持续时间、缓动、延迟等参数。大多数子属性是可选的,但必须指定名称和持续时间。点击此处了解更多信息。

虽然本教程中不会用到,但实际应用中的 CSS 动画声明和@keyframes规则都需要浏览器厂商前缀才能在所有现代浏览器中正常工作:

.square {
  -webkit-animation: rotation 5s linear infinite;
  -moz-animation:    rotation 5s linear infinite; 
  -o-animation:      rotation 5s linear infinite; 
  animation:         rotation 5s linear infinite; 
}
Enter fullscreen mode Exit fullscreen mode
-webkit-@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}

-moz-@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}

-o-@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}

@keyframes rotation {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}
Enter fullscreen mode Exit fullscreen mode

为我们的 CSS 宝丽来动画

现在我们已经掌握了基础知识,接下来让我们为 CSS 宝丽来相机添加动画。我希望创建一个动画序列,首先按下按钮,然后闪烁指示灯,接着缩放功能旋转,最后闪光灯熄灭。之后,动画将无限循环播放。

通常不建议使用 CSS 关键帧创建动画序列,因为没有简单的方法可以将多个独立的动画串联起来。相反,你必须精确地控制每个关键帧的触发时间,确保它们在正确的时间点触发。如果动画很复杂,这会很快变得很麻烦,但这个动画足够简单,我认为它会是一个很好的练习!让我们开始吧。

首先,我们还缺少一个元素:手电筒。让我们快速添加它:

.polaroid
  .button
  .flash
  .polaroid-body
  .blinker
  .stripes
  .zoom
    .reflections
.flashlight
Enter fullscreen mode Exit fullscreen mode
.flashlight {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background: rgba(white, 0.7);
  transition: all ease 0.2s;
  opacity: 0;
}
Enter fullscreen mode Exit fullscreen mode

我打破了规则,将手电筒元素放在了主容器之外。这是因为我希望它占据屏幕的全部宽度和高度。我还将其不透明度设置为 0,因为我们目前不想让它可见。

第一个动画是按下按钮。按钮需要向下移动,然后回到原来的位置,就像这样:

@keyframes button {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(10px);
  }
  100% {
    transform: translateY(0);
  }
}
Enter fullscreen mode Exit fullscreen mode

然后我们可以在.button选择器中调用这条规则:

.button {
  //...
  animation: button 5s linear infinite;
}
Enter fullscreen mode Exit fullscreen mode

这看起来不太对劲,动画太慢了。我们把动画持续时间设为了 5 秒,但这应该是包含所有四个动画的整个序列的总时长。我们需要缩短这个动画的时长。让它在 5% 到 15% 之间播放。

@keyframes button {
  0% {
    transform: translateY(0);
  }
  5% {
    transform: translateY(0);
  }
  10% {
    transform: translateY(10px);
  }
  15% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(0);
  }
}
Enter fullscreen mode Exit fullscreen mode

我们可以走捷径,这样写:

@keyframes button {
  0%, 5%, 15%, 100% {
    transform: translateY(0);
  }
  10% {
    transform: translateY(10px);
  }
}
Enter fullscreen mode Exit fullscreen mode

最后,如果我们仔细观察时间线,会发现按钮在 0% 到 5% 之间,或者在 15% 到 100% 之间没有动画效果。动画只在 5% 到 15% 之间运行,在 5 秒时间线的任何其他点,它都处于其原始的、未转换的状态:(translateY(0))。

因此,不需要起始和结束关键帧选择器:

@keyframes button {
  5%, 15%{
    transform: translateY(0);
  }
  10% {
    transform: translateY(10px);
  }
}
Enter fullscreen mode Exit fullscreen mode

我上面说的是“原始状态”,因为该.button元素一开始就没有被赋予 transform 属性。例如,如果我们有以下代码:

.button {
  transform: translateY(-20px);
}
Enter fullscreen mode Exit fullscreen mode

那么上述快捷方式就无法正常工作,因为按钮从 15% 到 100% 的过程中会重新回到原来的位置。

现在我们来看第二个动画,缩放旋转。让它从 20% 的位置开始,旋转 20 度,持续 6% 的总时间,然后再旋转回初始位置,持续 6%。

@keyframes zoom {
  20%, 32%  {
    transform: rotate(0deg);
  }
  26% {
    transform: rotate(20deg);
  }
}

.zoom {
  //...
  animation: zoom 5s linear infinite;
}
Enter fullscreen mode Exit fullscreen mode

酷。现在我们来制作转向灯动画。我们要改变背景颜色,让它闪烁三次红色。

@keyframes blinker {
  33%, 37%, 39%, 43%, 45%, 50% {
    background-color: $dark-grey;
  }
  34%, 36%, 40%, 42%, 46%, 48% {
    background-color: $red
  }
}

.blinker { 
  //... 
  animation: blinker 5s linear infinite; 
}
Enter fullscreen mode Exit fullscreen mode

它从33%开始,然后过渡到红色背景,持续1%的总时长,然后暂停2%,再过渡回灰色,持续1%。这个过程重复2次。

你可以看出,在这种情况下,能够将独立的动画串联或循环播放会非常有用。如果能定义一个眨眼动画,然后设置它重复两次,而不是定义那么多关键帧选择器,那就太好了。可惜的是,CSS 并没有提供这个选项,所以我们只能通过这种计算方式来实现想要的效果。

最后,是Flash动画:

@keyframes flashlight {
  55%, 65% {
    opacity: 0;
  }
  56% {
    opacity: 1;
  }
}

.flash-light { 
  //... 
  animation: flashlight 5s linear infinite; 
}
Enter fullscreen mode Exit fullscreen mode

我们的动画可以到此结束。65%到100%之间不会发生任何事情:这会在动画重新开始之前产生一个舒适的停顿。

我们还可以做的最后一件事是将动画持续时间存储到一个变量中:

$duration: 5s;

.button {
  //...
  animation: button $duration linear infinite;
}
.zoom {
  //...
  animation: zoom $duration linear infinite;
}
.blinker { 
  //... 
  animation: blinker $duration linear infinite; 
}
.flash-light { 
  //... 
  animation: flash-light $duration linear infinite; 
}
Enter fullscreen mode Exit fullscreen mode

这样一来,如果我们需要的话,就可以非常轻松地改变动画速度。

这是 CodePen 上的最终项目。

现在你应该已经很好地掌握了如何创建纯 CSS 图片。让我们最后再练习一下这些概念。在本系列的第三部分,也是最后一部分中,我们将学习一些构建动画灯塔场景的新技术。

第三部分:CSS Lighthouse 场景的更高级技巧

文章来源:https://dev.to/agathacco/how-to-create-pure-css-illustrations-and-animate-them---part-2-1ao4