如何使用 CSS 创建动画 SVG 脸

2025-06-08

如何使用 CSS 创建动画 SVG 脸

了解如何使用 CSS 动画、变换和可选的 JavaScript 创建动画 SVG 脸。

这是我的网络应用程序ButtonBuddy.dev中使用的动画的独立演示,您可以在其中了解可访问的按钮对比度,然后生成您自己的可访问按钮调色板。

以下是允许您改变 Buddy 情绪的演示预览:

带有面部 SVG 和 3 个单选按钮选项的按钮

创建 SVG 脸部

我们可以使用两个 SVG 元素来实现基本脸部:

  • 两只ellipse眼睛
  • 一个path用于嘴巴

但首先我们需要我们的基本 SVG 元素,我们将为其包含一个viewBox属性,该属性充当 SVG 的窗口并提供 SVG 宽高比的提示:



<svg viewBox="0 0 100 60"></svg>


Enter fullscreen mode Exit fullscreen mode

接下来,我们来添加眼睛。除了属性之外,它们几乎完全相同,该属性会沿着cx的位置移动ellipsex-axis



<svg viewBox="0 0 100 60">
  <ellipse cx="15" cy="12" rx="8" ry="9" class="eye right-eye" fill="currentColor" />
  <ellipse cx="80" cy="12" rx="8" ry="9" class="eye left-eye" fill="currentColor" />
</svg>


Enter fullscreen mode Exit fullscreen mode

我们添加fill="currentColor"以便颜色默认为 SVG 最接近祖先的文本颜色。

您可以查看MDN 文档ellipse以获取有关其他属性的更多信息。

最后,我们添加一个path来表示微笑:



<svg viewBox="0 0 100 60">
  <!-- (ellipses) -->
  <path 
    stroke-linecap="round" 
    d="M30 40 c0 20, 40 20, 40 0" 
    fill="currentColor" stroke="currentColor" />
</svg>


Enter fullscreen mode Exit fullscreen mode

让我们分解一下属性:

  • stroke-linecap="round"- 这会将路径描边的默认“端点”从方形改为更柔和的端点。这在“高兴”和“悲伤”情绪中表现得最为明显。
  • fill并且stroke——我们再次使用currentColoras describe 来表示ellipses。用它来fill创建张嘴微笑的外观,以表示我们默认的情绪“兴奋”。
  • d- 这就是绘制路径的内容。
    1. M30 40将起点(笑脸左侧的点)分别定位到30x 轴上的 位置 和40y 轴上的 位置 。这相对于我们的viewBox
    2. c接下来,我们通过创建对来创建一条曲线x y。每两个数字组成一对,因此0 20意味着0x 20y。这些值与 相对M,并为 SVG 创建控制点,以便按照 MDN 文档 中的说明绘制贝塞尔曲线

这是带有贝塞尔曲线控制点的面:

SVG 脸部在嘴巴上方和周围有四个红点,一个在左上方,一个在宽度的 30% 处,一个在下方约 5% 处,一个在宽度的 60% 处,一个在下方约 5% 处,最后一个在右上角

塑造情感

我们的第一个情绪“兴奋”是如上所述的默认状态。

对于“高兴”和“悲伤”表情,我们希望移除fillpath将嘴部外观改为闭嘴微笑。我们还将增加stroke-width



svg.happy path,
svg.sad path {
  fill: transparent;
  stroke-width: 6px;
}


Enter fullscreen mode Exit fullscreen mode

完整的演示展示了如何使用clamp更加动态的大小stroke-width和按钮font-size

对于悲伤,我们需要将笑脸翻转过来,我们可以通过 CSS 变换快速实现这一点:



svg.sad path {
  transform: scaleY(-1);
  transform-origin: 50% 80%;
}


Enter fullscreen mode Exit fullscreen mode

水平翻转元素。由于scaleY(-1)SVG 中有多个元素,我们还必须使用transform-origin来确保 的变换path是相对于其原始位置的。说实话,找到这些值需要一些反复试验 :)

在演示中,您还会看到添加了过渡效果,以便从一种情绪平滑过渡到另一种情绪。总而言之,这些属性可以实现简单而有效的动画,而无需引入动画框架。

眨眼动画

眨眼transform动画也使用了 中的“但是” @keyframes。我们交替使用“眯眼”(通过压平眼睛来实现ellipse)和完全睁开来产生眨眼效果:



@keyframes wink {
  0%,
  20%,
  70% {
    transform: scale(1.5, 0.25);
  }

  30%,
  50%,
  90%,
  100% {
    transform: scale(1);
  }
}


Enter fullscreen mode Exit fullscreen mode

斜视使用了一种类似于球体挤压的经典动画技巧,在函数中,它同时略微加宽元素( 1.5)并减小其高度( ) 。这些数字是计算出的元素大小的比例。因此,为了使其恢复到原始大小,我们将两者的值都更新为(由于两者的值相同,因此我们可以用一个数字来定义)。0.25scale1

要应用wink动画,请使用以下 CSS 规则:



svg.wink .eye:last-of-type {
  /* Ensure the default element is at normal scale */
  transform: scale(1);
  transform-origin: 90% 20%;
  animation: wink 480ms ease-in-out 1;
}


Enter fullscreen mode Exit fullscreen mode

再次,我们必须transform-origin根据与微笑相同的理由进行调整path

480ms我们应用了持续时间为、缓动函数为 的动画ease-in-out,并播放了1一次。

但是你可能在开头的预览 gif 中注意到了(或者如果你直接跳到演示版),眨眼动画会时不时地重复出现。为此,我们需要添加一些 JavaScript 代码来重新触发动画。

最小的 Javascript 找到 SVG 元素,然后毫秒(5 秒)setInterval添加一次类。wink5000

重要的是,我们添加了一个事件监听器来animationend移除该类wink添加和移除该类wink允许按间隔重新启动动画。



const buddy = document.querySelector(".buddy svg");

setInterval(() => {
  buddy.classList.add("wink");
}, 5000);

// Remove the wink class to reset the animation after it ends
buddy.addEventListener("animationend", () => {
  buddy.classList.remove("wink");
});


Enter fullscreen mode Exit fullscreen mode

该演示包括一个额外的检查,仅wink当 Buddy 不“悲伤”时才允许添加该类。

演示

您可以在此 CodePen 中查看完整的演示,然后查看ButtonBuddy.dev来创建您自己的可访问按钮调色板!

如果您喜欢本教程和ButtonBuddy,请查看我在ModernCSS.dev上的其他 CSS 资源,并考虑请我喝杯咖啡

鏂囩珷鏉ユ簮锛�https://dev.to/5t3ph/how-to-create-an-animated-svg-face-with-css-5djd
PREV
Web 可访问性简介
NEXT
我如何在 17 小时内构建并发布一个小型 Web 应用