DevToolBox免费
博客

CSS 动画与 @keyframes 示例

11 分钟阅读作者 DevToolBox

CSS 动画无需 JavaScript 即可让网页焕发生机。使用 @keyframesanimation 简写属性,你可以创建从微妙的淡入到复杂多步骤序列的各种效果。本完整 CSS 动画与 @keyframes 指南涵盖语法、时间函数、性能优化、无障碍访问以及数十个可直接复制使用的示例。

使用我们的 CSS 渐变生成器创建渐变动画 ->

使用我们的盒阴影生成器制作阴影动画 ->

1. @keyframes 语法

@keyframes 规则定义动画的各个阶段。你为它指定一个名称,然后描述在动画时间线的每个点上应该应用什么 CSS 属性。浏览器会在每个定义的步骤之间平滑插值。

from / to (Two-Step)

/* Simple two-step animation using from/to */
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* from = 0%, to = 100% */
.element {
  animation: fade-in 0.5s ease;
}

Percentage Steps (Multi-Step)

/* Multi-step animation with percentage keyframes */
@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  25% {
    transform: translateY(-30px);
  }
  50% {
    transform: translateY(0);
  }
  75% {
    transform: translateY(-15px);
  }
  100% {
    transform: translateY(0);
  }
}

/* You can combine from/to with percentages */
@keyframes color-shift {
  0%, 100% { background-color: #3b82f6; }
  25%      { background-color: #8b5cf6; }
  50%      { background-color: #ec4899; }
  75%      { background-color: #f59e0b; }
}

Multiple Properties in Keyframes

@keyframes slide-in-fade {
  0% {
    opacity: 0;
    transform: translateX(-100px);
  }
  60% {
    opacity: 1;
    transform: translateX(10px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

命名约定:使用小写连字符命名法(例如 fade-inslide-up)。避免使用 animation1 这样的通用名称。名称区分大小写,且不能与 CSS 关键字(如 noneinheritinitial)冲突。

2. animation 简写属性

animation 简写属性将所有动画子属性合并为一个声明。持续时间和延迟之间的区分取决于顺序(第一个时间值是持续时间,第二个是延迟),其他属性顺序灵活。

各个子属性包括:animation-name(名称)、animation-duration(持续时间)、animation-timing-function(时间函数)、animation-delay(延迟)、animation-iteration-count(迭代次数)、animation-direction(方向)、animation-fill-mode(填充模式)和 animation-play-state(播放状态)。

/* animation shorthand syntax */
animation: name duration timing-function delay iteration-count direction fill-mode play-state;

/* Examples */
animation: fade-in 0.3s ease;
animation: slide-up 0.5s ease-out 0.2s;
animation: spin 1s linear infinite;
animation: bounce 0.6s ease-in-out 0s infinite alternate;
animation: fade-in 0.5s ease forwards;

/* Individual properties (equivalent to above) */
.element {
  animation-name: fade-in;
  animation-duration: 0.5s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: running;
}

/* Multiple animations on one element */
.element {
  animation:
    fade-in 0.5s ease,
    slide-up 0.5s ease 0.1s,
    color-shift 3s linear infinite;
}

/* fill-mode values */
animation-fill-mode: none;      /* default: no styles applied outside animation */
animation-fill-mode: forwards;  /* retains the final keyframe styles */
animation-fill-mode: backwards; /* applies first keyframe styles during delay */
animation-fill-mode: both;      /* combines forwards + backwards */

/* direction values */
animation-direction: normal;            /* 0% -> 100% */
animation-direction: reverse;           /* 100% -> 0% */
animation-direction: alternate;         /* 0% -> 100% -> 0% -> ... */
animation-direction: alternate-reverse; /* 100% -> 0% -> 100% -> ... */

3. 时间函数(Timing Functions)

时间函数控制动画的加速曲线,决定关键帧之间中间值的计算方式,赋予动画独特的节奏和感觉。

/* Built-in keyword timing functions */
animation-timing-function: ease;        /* default: slow start, fast, slow end */
animation-timing-function: linear;      /* constant speed */
animation-timing-function: ease-in;     /* slow start, fast end */
animation-timing-function: ease-out;    /* fast start, slow end */
animation-timing-function: ease-in-out; /* slow start and end */

/* Equivalent cubic-bezier() values */
ease:        cubic-bezier(0.25, 0.1, 0.25, 1.0)
linear:      cubic-bezier(0.0,  0.0, 1.0,  1.0)
ease-in:     cubic-bezier(0.42, 0.0, 1.0,  1.0)
ease-out:    cubic-bezier(0.0,  0.0, 0.58, 1.0)
ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0)

/* Custom cubic-bezier examples */
animation-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); /* back-in-out */
animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);       /* overshoot */
animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);       /* ease-out-cubic */

cubic-bezier() 接受四个值(x1, y1, x2, y2)定义三次贝塞尔曲线的控制点。y 轴超出 0-1 范围的值会产生过冲/弹跳效果。使用浏览器开发者工具或在线工具可视化曲线。

/* steps() function for frame-by-frame animations */
animation-timing-function: steps(4);            /* 4 equal jumps, default jump-end */
animation-timing-function: steps(4, jump-start); /* jump at start of each interval */
animation-timing-function: steps(4, jump-end);   /* jump at end of each interval */
animation-timing-function: steps(4, jump-both);   /* jump at start and end */
animation-timing-function: steps(4, jump-none);   /* no jump at start or end */
animation-timing-function: step-start;           /* = steps(1, jump-start) */
animation-timing-function: step-end;             /* = steps(1, jump-end) */

/* Sprite sheet animation example */
.sprite {
  width: 64px;
  height: 64px;
  background: url('spritesheet.png') 0 0;
  animation: walk 0.8s steps(8) infinite;
}

@keyframes walk {
  to { background-position: -512px 0; } /* 64px * 8 frames = 512px */
}

steps() 创建阶梯函数,在状态之间跳跃而非平滑插值。可选的第二个参数(jump-startjump-endjump-bothjump-none)控制跳跃发生的时机。这对精灵图动画至关重要。

4. 常用动画(复制即用)

这些是 Web 开发中最常用的动画效果。每个示例都可以直接用于生产环境——只需复制 CSS 并将类名应用到你的元素上。

Fade In

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.fade-in {
  animation: fadeIn 0.5s ease forwards;
}

Fade Out

@keyframes fadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}
.fade-out {
  animation: fadeOut 0.5s ease forwards;
}

Slide In from Left

@keyframes slideInLeft {
  from {
    opacity: 0;
    transform: translateX(-60px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}
.slide-in-left {
  animation: slideInLeft 0.5s ease-out forwards;
}

Slide In from Bottom

@keyframes slideInUp {
  from {
    opacity: 0;
    transform: translateY(40px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.slide-in-up {
  animation: slideInUp 0.5s ease-out forwards;
}

Bounce

@keyframes bounce {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-30px);
  }
  60% {
    transform: translateY(-15px);
  }
}
.bounce {
  animation: bounce 1s ease infinite;
}

Pulse

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.05);
    opacity: 0.8;
  }
}
.pulse {
  animation: pulse 2s ease-in-out infinite;
}

Spin

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.spin {
  animation: spin 1s linear infinite;
}

Shake

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
  20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake {
  animation: shake 0.6s ease-in-out;
}

/* Trigger shake on invalid input */
input:invalid:focus {
  animation: shake 0.4s ease-in-out;
}

5. Transform 变换动画

transform 属性非常适合做动画,因为它由 GPU 加速且不会触发布局重新计算。你可以在一个声明中组合多个变换函数来实现复杂的运动效果。

Rotate

@keyframes rotate360 {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Pendulum swing */
@keyframes pendulum {
  0%   { transform: rotate(-30deg); }
  50%  { transform: rotate(30deg); }
  100% { transform: rotate(-30deg); }
}
.pendulum {
  transform-origin: top center;
  animation: pendulum 2s ease-in-out infinite;
}

Scale

/* Pop-in effect */
@keyframes popIn {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  70% {
    transform: scale(1.1);
    opacity: 1;
  }
  100% {
    transform: scale(1);
  }
}
.pop-in {
  animation: popIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}

/* Heartbeat */
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  14%      { transform: scale(1.3); }
  28%      { transform: scale(1); }
  42%      { transform: scale(1.3); }
  70%      { transform: scale(1); }
}
.heartbeat {
  animation: heartbeat 1.5s ease-in-out infinite;
}

Translate

/* Floating effect */
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-20px); }
}
.float {
  animation: float 3s ease-in-out infinite;
}

/* Marquee scroll */
@keyframes marquee {
  from { transform: translateX(100%); }
  to   { transform: translateX(-100%); }
}
.marquee {
  animation: marquee 10s linear infinite;
}

Skew

@keyframes skewShake {
  0%, 100% { transform: skewX(0deg); }
  25%      { transform: skewX(5deg); }
  75%      { transform: skewX(-5deg); }
}
.skew-shake {
  animation: skewShake 0.5s ease-in-out;
}

Combined Transforms

/* Rotate + Scale + Translate combined */
@keyframes complexEntry {
  0% {
    transform: translateY(50px) rotate(-10deg) scale(0.8);
    opacity: 0;
  }
  100% {
    transform: translateY(0) rotate(0deg) scale(1);
    opacity: 1;
  }
}
.complex-entry {
  animation: complexEntry 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

/* 3D flip */
@keyframes flip {
  0%   { transform: perspective(600px) rotateY(0deg); }
  100% { transform: perspective(600px) rotateY(360deg); }
}
.flip {
  animation: flip 1s ease-in-out;
}

6. JavaScript 中的动画事件

CSS 动画触发三个可以用 JavaScript 监听的事件:animationstart(开始)、animationend(结束)和 animationiteration(每次迭代)。这些事件让你可以将 JavaScript 逻辑与 CSS 动画状态同步。

const element = document.querySelector('.animated');

// Fires when the animation starts (after any delay)
element.addEventListener('animationstart', (e) => {
  console.log(`Animation "${e.animationName}" started`);
  console.log(`Duration: ${e.elapsedTime}s`);
});

// Fires when the animation completes
element.addEventListener('animationend', (e) => {
  console.log(`Animation "${e.animationName}" ended`);
  // Common pattern: remove the animation class after completion
  element.classList.remove('animate');
});

// Fires at the end of each iteration (except the last)
element.addEventListener('animationiteration', (e) => {
  console.log(`Animation "${e.animationName}" completed iteration`);
  console.log(`Elapsed time: ${e.elapsedTime}s`);
});

Practical Example: One-Shot Animation

/* CSS */
.notification-enter {
  animation: slideInRight 0.4s ease-out forwards;
}

@keyframes slideInRight {
  from { transform: translateX(100%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

/* JavaScript: remove class after animation so it can replay */
document.querySelectorAll('.notification').forEach(el => {
  el.addEventListener('animationend', () => {
    el.classList.remove('notification-enter');
  });
});

/* Re-trigger: remove and re-add class with a reflow in between */
function triggerAnimation(el) {
  el.classList.remove('notification-enter');
  // Force reflow to restart animation
  void el.offsetWidth;
  el.classList.add('notification-enter');
}

注意:如果动画在完成前被移除(例如移除了类名),animationend 事件不会触发。animationiteration 事件在每次迭代结束时触发,但最后一次迭代除外。

7. Transition 与 Animation 对比

CSS 过渡和动画都能创建运动效果,但它们有不同的用途和能力。理解何时使用哪个对于编写整洁、可维护的 CSS 至关重要。

Feature transition animation
Trigger requiredYes (:hover, :focus, class change)No (auto-plays)
Number of states2 (start + end)Unlimited (@keyframes)
LoopingNoYes (infinite)
Direction controlAuto-reverses on state changenormal, reverse, alternate
Play stateNo pause/resumepaused / running
Fill modeImplicit (stays in end state)none, forwards, backwards, both
JS Eventstransitionendanimationstart, animationend, animationiteration
Best forHover effects, toggles, interactive UILoading states, attention seekers, complex sequences
/* TRANSITION: hover color change */
.button {
  background: #3b82f6;
  transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
  background: #2563eb;
  transform: translateY(-2px);
}

/* ANIMATION: autonomous pulsing glow */
@keyframes glow {
  0%, 100% { box-shadow: 0 0 5px #3b82f6; }
  50%      { box-shadow: 0 0 20px #3b82f6, 0 0 40px #3b82f680; }
}
.notification-badge {
  animation: glow 2s ease-in-out infinite;
}

经验法则:对用户交互触发的简单状态变化(hover、focus、class 切换)使用 transition。对复杂的、自主的、多步骤的或循环的运动使用 animation

8. 性能优化

并非所有 CSS 属性动画的性能都相同。有些会触发昂贵的布局重新计算,而有些完全由 GPU 合成器处理。理解这个区别是实现流畅 60fps 动画的关键。

GPU 加速属性:transformopacity 在 GPU 上合成,跳过布局和绘制阶段。动画应始终优先使用这两个属性。

/* GOOD: GPU-accelerated, no layout or paint */
@keyframes slide {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

/* BAD: triggers layout on every frame */
@keyframes slide-bad {
  from { left: -100%; opacity: 0; }
  to   { left: 0; opacity: 1; }
}

will-change:此属性向浏览器提示元素将被动画化,使其可以提前优化。但要谨慎使用——对过多元素应用 will-change 会浪费 GPU 内存。

/* Apply will-change before animation starts */
.card {
  will-change: transform;
  transition: transform 0.3s ease;
}
.card:hover {
  transform: translateY(-5px);
}

/* Remove will-change after animation completes */
.animated-element {
  will-change: transform, opacity;
}
.animated-element.done {
  will-change: auto; /* release GPU memory */
}

避免动画化:widthheighttopleftmarginpaddingborder-widthfont-size。这些会触发布局(回流),是最昂贵的渲染操作。用 transform: translate() 代替 top/left,用 transform: scale() 代替 width/height

/* INSTEAD OF animating width: */
/* Bad */
@keyframes expand-bad {
  from { width: 0; }
  to   { width: 200px; }
}

/* Good: use scaleX */
@keyframes expand-good {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.expand {
  transform-origin: left center;
  animation: expand-good 0.5s ease forwards;
}

/* INSTEAD OF animating top/left: */
/* Bad */
@keyframes move-bad {
  from { top: 0; left: 0; }
  to   { top: 100px; left: 200px; }
}

/* Good: use translate */
@keyframes move-good {
  from { transform: translate(0, 0); }
  to   { transform: translate(200px, 100px); }
}

9. prefers-reduced-motion(无障碍访问)

部分用户会因动画而感到眩晕、癫痫发作或不适。prefers-reduced-motion 媒体查询让你可以尊重他们的系统偏好设置。这不是可选的——它是 WCAG 2.1(成功标准 2.3.3)下的无障碍要求。

有两种方法:(1)为偏好减少动效的用户移除动画,或(2)仅为没有偏好的用户添加动画。第二种方法(渐进增强)被认为更安全。

Approach 1: Remove Animations

/* Remove all animations and transitions for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Approach 2: Progressive Enhancement (Recommended)

/* Default: no animation */
.card {
  opacity: 1;
  transform: none;
}

/* Only animate if user has no motion preference */
@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: fadeInUp 0.5s ease forwards;
  }

  @keyframes fadeInUp {
    from {
      opacity: 0;
      transform: translateY(20px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

JavaScript Detection

// Check if user prefers reduced motion
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches;

if (prefersReducedMotion) {
  // Skip animation, show content immediately
  element.style.opacity = '1';
} else {
  element.classList.add('animate-in');
}

// Listen for changes (user toggles setting)
window.matchMedia('(prefers-reduced-motion: reduce)')
  .addEventListener('change', (e) => {
    if (e.matches) {
      document.body.classList.add('reduce-motion');
    } else {
      document.body.classList.remove('reduce-motion');
    }
  });

10. 加载旋转器(纯 CSS)

加载旋转器是 CSS 动画最常见的应用之一。以下是 5 种不同风格,全部使用纯 CSS 实现,无需 JavaScript 或图片。

1. Classic Border Spinner

.spinner-border {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(59, 130, 246, 0.2);
  border-top-color: #3b82f6;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

2. Dual Ring Spinner

.spinner-dual {
  width: 40px;
  height: 40px;
  border: 4px solid transparent;
  border-top-color: #3b82f6;
  border-bottom-color: #8b5cf6;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

3. Pulsing Dot

.spinner-pulse {
  width: 20px;
  height: 20px;
  background: #3b82f6;
  border-radius: 50%;
  animation: pulse-spinner 1.2s ease-in-out infinite;
}

@keyframes pulse-spinner {
  0%, 100% {
    transform: scale(0.5);
    opacity: 0.5;
  }
  50% {
    transform: scale(1);
    opacity: 1;
  }
}

4. Three Bouncing Dots

.spinner-dots {
  display: flex;
  gap: 6px;
}
.spinner-dots span {
  width: 10px;
  height: 10px;
  background: #3b82f6;
  border-radius: 50%;
  animation: dot-bounce 1.4s ease-in-out infinite;
}
.spinner-dots span:nth-child(1) { animation-delay: 0s; }
.spinner-dots span:nth-child(2) { animation-delay: 0.2s; }
.spinner-dots span:nth-child(3) { animation-delay: 0.4s; }

@keyframes dot-bounce {
  0%, 80%, 100% {
    transform: scale(0.6);
    opacity: 0.5;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

/* HTML: <div class="spinner-dots"><span></span><span></span><span></span></div> */

5. Rotating Squares

.spinner-squares {
  width: 40px;
  height: 40px;
  position: relative;
}
.spinner-squares::before,
.spinner-squares::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 4px;
  background: #3b82f6;
}
.spinner-squares::before {
  animation: square-rotate 2s ease infinite;
}
.spinner-squares::after {
  animation: square-rotate 2s ease infinite 1s;
  opacity: 0.5;
}

@keyframes square-rotate {
  0%   { transform: rotate(0deg) scale(1); }
  25%  { transform: rotate(90deg) scale(0.6); }
  50%  { transform: rotate(180deg) scale(1); }
  75%  { transform: rotate(270deg) scale(0.6); }
  100% { transform: rotate(360deg) scale(1); }
}

11. 滚动触发动画

滚动触发动画在用户向下滚动页面时逐步展示内容。现代方法使用 Intersection Observer API 在元素进入视口时添加 CSS 类,将动画逻辑保留在 CSS 中,触发逻辑使用最少的 JavaScript。

Intersection Observer + CSS Classes

/* CSS: define the animation and the initial hidden state */
.reveal {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Staggered children */
.reveal.visible .child:nth-child(1) { transition-delay: 0s; }
.reveal.visible .child:nth-child(2) { transition-delay: 0.1s; }
.reveal.visible .child:nth-child(3) { transition-delay: 0.2s; }
// JavaScript: Intersection Observer
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add('visible');
        // Optional: stop observing after first trigger
        observer.unobserve(entry.target);
      }
    });
  },
  {
    threshold: 0.1,     // Trigger when 10% visible
    rootMargin: '0px 0px -50px 0px' // Offset trigger point
  }
);

// Observe all elements with the .reveal class
document.querySelectorAll('.reveal').forEach((el) => {
  observer.observe(el);
});

CSS Scroll-Driven Animations (Chrome / Edge)

/* Pure CSS scroll-triggered animation (no JavaScript!) */
/* Supported in Chrome 115+ and Edge 115+ */

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(50px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.scroll-reveal {
  animation: reveal linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

/* Scroll progress bar at top of page */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(90deg, #3b82f6, #8b5cf6);
  transform-origin: left;
  animation: scaleProgress linear;
  animation-timeline: scroll();
}

@keyframes scaleProgress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

纯 CSS 方案:新的 animation-timeline: scroll()animation-timeline: view() 属性已在 Chrome 和 Edge 中支持,允许无需任何 JavaScript 实现滚动驱动动画。

12. 常见问题

CSS transition 和 CSS animation 有什么区别?

CSS 过渡需要触发器(如 :hover 或类名变化),且只能在两个状态(起始和结束)之间动画。CSS 动画使用 @keyframes 可以自动运行、无限循环、定义多个中间步骤、反向播放以及暂停/恢复。简单的交互状态变化用 transition;复杂的、自主的或多步骤效果用 animation。

如何让 CSS 动画无限循环?

设置 animation-iteration-count: infinite 或使用简写:animation: spin 1s linear infinite。动画将无限期重复,直到元素被移除或 animation 属性被更改。你还可以使用 JavaScript 的 animationiteration 事件在每次循环时执行操作。

为什么我的 CSS 动画卡顿或不流畅?

动画卡顿通常是因为对触发布局的属性(width、height、top、left、margin)或绘制的属性(background-color、box-shadow、border-radius)做了动画。应改用 transformopacity,它们在 GPU 上合成。同时给动画元素添加 will-change: transform,并确保不要同时动画化太多元素。

如何暂停和恢复 CSS 动画?

使用 animation-play-state 属性。设为 paused 可在当前位置冻结动画,设为 running 可恢复播放。示例:.paused { animation-play-state: paused; }。你可以用 JavaScript 通过添加/移除类来切换。

如何在元素滚动到视口时触发 CSS 动画?

使用 JavaScript 的 Intersection Observer API 检测元素何时进入视口,然后添加一个启动动画的 CSS 类。在类上定义动画(例如 .animate-in { animation: fadeIn 0.6s ease forwards; }),并在观察到元素时添加该类。对于现代浏览器(Chrome/Edge),还可以使用原生 CSS animation-timeline: view() 属性实现纯 CSS 方案。

CSS 动画是增强用户体验的强大、高性能方式。结合无障碍实践和 GPU 优化属性,它们可以让任何 Web 应用看起来精致而专业。

使用我们的 CSS 渐变生成器创建渐变动画 ->

使用我们的盒阴影生成器制作阴影动画 ->

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

🌈CSS Gradient Generator🔲Box Shadow Generator{ }CSS Minifier / Beautifier

相关文章

CSS 渐变指南:从基础到高级技巧

掌握 CSS 渐变:线性、径向、锥形、重复渐变,包含实用示例、文字渐变效果和性能优化建议。

CSS 文字渐变:如何用纯 CSS 创建渐变文字

用 CSS 创建炫酷的渐变文字。使用 background-clip、-webkit-text-fill-color 的分步指南,以及所有浏览器的降级策略。