0Pricing
Tailwind CSS Academy · 课时

在配置中创建自定义动画

在 tailwind.config.js 中定义自定义关键帧和动画实用程序,并在标记中使用 animate-* class 引用它们。

在配置中创建自定义动画 是 CoddyKit 上的免费 Tailwind CSS Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Tailwind CSS Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Tailwind CSS Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Beyond the Four Built-In Animations

Tailwind's four built-in animations cover common loading and attention patterns, but real projects often need additional animations: fade-in effects for content entrance, slide-in sidebars, shake effects for form errors, or custom pulse variations. By adding entries to theme.extend.keyframes and theme.extend.animation in your config, you create new animate-* utilities that work exactly like the built-ins.

Defining Custom Keyframes

Add custom CSS keyframes in theme.extend.keyframes. Each key in the object becomes a keyframe name. The value is an object where keys are percentage strings or 'from'/'to' keywords, and values are CSS property objects. Tailwind converts this object notation to the @keyframes CSS rule in the compiled output. You can use any animatable CSS property inside the keyframe steps.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        // Fade in from transparent
        'fade-in': {
          '0%':   { opacity: '0' },
          '100%': { opacity: '1' },
        },
        // Slide up from below
        'slide-up': {
          '0%':   { opacity: '0', transform: 'translateY(16px)' },
          '100%': { opacity: '1', transform: 'translateY(0)' },
        },
        // Shake (for errors)
        'shake': {
          '0%, 100%': { transform: 'translateX(0)' },
          '20%, 60%': { transform: 'translateX(-8px)' },
          '40%, 80%': { transform: 'translateX(8px)' },
        },
      },
    },
  },
};

Registering Custom Animation Utilities

After defining keyframes, register them as named animations in theme.extend.animation. The value is a CSS animation shorthand string: name duration timing-function delay iteration-count direction fill-mode. The name must match a keyframe defined in theme.extend.keyframes. Tailwind generates an animate-{key} utility class for each entry.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: { /* ... defined above ... */ },
      animation: {
        'fade-in':  'fade-in 0.3s ease-out',
        'slide-up': 'slide-up 0.4s ease-out',
        'shake':    'shake 0.5s ease-in-out 1',
        // Multiple values
        'fade-in-slow': 'fade-in 1s ease-in-out',
        // Infinite loop
        'fade-in-out': 'fade-in 1.5s ease-in-out infinite alternate',
      },
    },
  },
};

Using Custom Animations in HTML

Once registered in the config, custom animations are available as animate-{key} classes in your HTML. They work exactly like the built-in animate utilities and can be combined with responsive prefixes, state variants, and the motion-reduce: variant for accessibility. The animation plays when the class is present and stops when the class is removed — perfect for JavaScript-triggered entrance effects.

<!-- Fade in a card on page load -->
<div class="animate-fade-in bg-white rounded-xl p-6 shadow">
  Content fades in smoothly
</div>

<!-- Slide up with a slight delay using inline style -->
<div class="animate-slide-up" style="animation-delay: 150ms">
  Content slides up after 150ms delay
</div>

<!-- Shake an input on validation error -->
<input
  id="email"
  class="border border-red-500 animate-shake focus:outline-none px-4 py-2 rounded-lg w-full"
  type="email"
  placeholder="Invalid email"
/>

Entrance Animations for Content

Entrance animations (fade-in, slide-up, scale-in) make content feel alive as it appears. They are most effective when content enters the viewport for the first time — on page load or when a section becomes visible during scrolling. Keep entrance durations between 200–400ms and always pair them with appropriate easing. Use the Intersection Observer API in JavaScript to trigger animations when elements scroll into view.

// JavaScript: trigger animation when element enters viewport
const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('animate-slide-up');
      observer.unobserve(entry.target); // animate once
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll('.animate-on-scroll').forEach((el) => {
  observer.observe(el);
});

<!-- HTML: starts invisible, gets class on scroll -->
<div class="opacity-0 animate-on-scroll">Animated on scroll</div>

More Complex Keyframe Examples

Complex animations use more keyframe percentage steps to create multi-stage motion. A heartbeat animation scales up then back down with a double-beat rhythm. A flash animation briefly highlights an element with a background color. A slide-in-right animation translates and fades simultaneously. These compound animations require multiple percentage steps to describe each stage of the motion precisely.

// tailwind.config.js
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)' },
  },
  'flash': {
    '0%, 50%, 100%': { opacity: '1' },
    '25%, 75%':      { opacity: '0.25' },
  },
  'slide-in-right': {
    '0%':   { opacity: '0', transform: 'translateX(32px)' },
    '100%': { opacity: '1', transform: 'translateX(0)' },
  },
},
animation: {
  'heartbeat':      'heartbeat 1.2s ease-in-out infinite',
  'flash':          'flash 0.5s ease-in-out',
  'slide-in-right': 'slide-in-right 0.3s ease-out',
}

Animation Fill Mode

The CSS animation-fill-mode property controls what happens before the animation starts (if there is a delay) and after it ends. forwards keeps the element in its final state after the animation ends — crucial for one-shot entrance animations where you want the element to stay visible. backwards applies the first frame during the delay period so elements start in the correct initial state. Include fill mode in your animation shorthand string.

// animation shorthand: name | duration | easing | delay | count | fill-mode
animation: {
  // 'forwards' keeps final state (element stays visible after fading in)
  'fade-in': 'fade-in 0.3s ease-out forwards',

  // 'backwards' applies frame-0 during delay (starts transparent during delay)
  'fade-in-delayed': 'fade-in 0.4s ease-out 0.2s backwards',

  // No fill mode: jumps back to initial state after animation
  'shake': 'shake 0.5s ease-in-out',
}

Pausing and Resuming Animations

You can pause a Tailwind animation using animation-play-state: paused. Add a custom utility class or use an arbitrary value: [animation-play-state:paused]. This is useful for pausing loading animations when a page is not visible (using the Page Visibility API) or pausing hover animations to give users time to interact with content. Tailwind does not have a built-in pause utility, but arbitrary CSS or a custom utility covers this.

@layer utilities {
  .animation-paused { animation-play-state: paused; }
  .animation-running { animation-play-state: running; }
}

<!-- Pause animation on hover -->
<div class="animate-pulse hover:animation-paused bg-gray-200 rounded h-4 w-48">
  Pauses pulsing when hovered
</div>

<!-- JavaScript: pause when page is hidden -->
document.addEventListener('visibilitychange', () => {
  const spinners = document.querySelectorAll('.animate-spin');
  spinners.forEach(el => {
    el.style.animationPlayState = document.hidden ? 'paused' : 'running';
  });
});

Respecting Reduced Motion in Custom Animations

Every custom animation you create should also have a motion-reduce: treatment. The simplest approach is motion-reduce:animate-none to disable the animation entirely. For entrance animations where you still want the final state to show, use motion-reduce:opacity-100 alongside motion-reduce:animate-none to ensure the element is visible even when the fade-in animation is skipped.

<!-- Accessible entrance animation -->
<div
  class="
    opacity-0 animate-fade-in
    motion-reduce:opacity-100 motion-reduce:animate-none
  "
>
  Content visible immediately for reduced-motion users,
  fades in for others
</div>

<!-- Accessible slide-up -->
<div
  class="
    opacity-0 translate-y-4 animate-slide-up
    motion-reduce:opacity-100 motion-reduce:translate-y-0 motion-reduce:animate-none
  "
>
  Reduced motion: appears instantly at final position
</div>

Third-Party Animation Libraries With Tailwind

For more sophisticated animations — spring physics, scroll-driven animations, or complex choreography — third-party libraries like tailwindcss-animate, Framer Motion (React), or GSAP integrate well with Tailwind. Tailwindcss-animate provides a rich set of pre-built keyframes (accordion-down, accordion-up, fade-in, etc.) as a plugin, instantly extending your available animate-* utilities. It is used by default in shadcn/ui components.

// Install tailwindcss-animate
// npm install tailwindcss-animate

// tailwind.config.js
module.exports = {
  plugins: [
    require('tailwindcss-animate'),
  ],
};

<!-- Now you have many new animate-* utilities -->
<div class="animate-in fade-in slide-in-from-bottom-4 duration-300">
  Animated with tailwindcss-animate
</div>

<div class="animate-out fade-out slide-out-to-top-4 duration-200">
  Exit animation
</div>

Debugging Custom Animations

Use Chrome DevTools' Animations panel to inspect and debug custom animations. Select the element in the Elements panel, then open the Animations panel. Run the animation and you will see the keyframe curve visualized with timing markers. You can slow down playback to 0.25x speed to carefully inspect each stage. The panel also lets you replay animations on demand, which is far easier than refreshing the page to catch entrance animations.

Quick Check

Test your understanding of custom animations in the Tailwind config.

Lesson Recap

In this lesson you learned: define custom keyframes in theme.extend.keyframes and register them as utilities in theme.extend.animation, use animation fill-mode forwards for one-shot entrance animations that should maintain their final state, and always pair custom animations with motion-reduce:animate-none for accessibility. This completes the Animations and Transitions course — next we build polished component patterns.

常见问题解答

「在配置中创建自定义动画」课时是免费的吗?

是的 — 「在配置中创建自定义动画」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Tailwind CSS Academy 课程的其余内容,请升级到 CoddyKit PRO。 Tailwind CSS Academy 课程共包含 4 节课。

「在配置中创建自定义动画」这节课中我会学到什么?

在 tailwind.config.js 中定义自定义关键帧和动画实用程序,并在标记中使用 animate-* class 引用它们。 你通过在浏览器中直接运行的动手代码来练习 Tailwind CSS Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Tailwind CSS Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Tailwind CSS Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「在配置中创建自定义动画」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Tailwind CSS Academy 课中编写并运行代码吗?

能。每节 Tailwind CSS Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 过渡实用程序
  2. 持续时间与缓动
  3. 内置关键帧动画
  4. 在配置中创建自定义动画
← 返回 Tailwind CSS Academy