nextjs-motion-animations

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js Motion Animation System

Next.js Motion 动画系统

A comprehensive animation system using Motion (formerly Framer Motion) v12.23.26 with performance-optimized patterns for Next.js applications.
一套基于 Motion(原 Framer Motion)v12.23.26 的全面动画系统,为 Next.js 应用提供性能优化的实现模式。

When to Use This Skill

何时使用该技能

Use this skill when you need to:
  • Add scroll-triggered animations to sections
  • Create interactive hover/tap animations
  • Implement staggered animations for lists
  • Add SVG path animations
  • Set up a centralized animation system
  • Optimize animation performance in Next.js
在以下场景中使用本技能:
  • 为页面区块添加滚动触发动画
  • 创建交互式悬停/点击动画
  • 为列表实现交错动画
  • 添加 SVG 路径动画
  • 搭建集中式动画系统
  • 优化 Next.js 中的动画性能

Core Animation Architecture

核心动画架构

Library Setup

库配置

  • Primary: Motion v12.23.26 (modern, lightweight alternative to framer-motion)
  • CSS Framework: TailwindCSS with custom animation utilities
  • Compatibility: React 19+ and Next.js 16+
  • 核心库:Motion v12.23.26(framer-motion 的现代轻量替代方案)
  • CSS 框架:带有自定义动画工具类的 TailwindCSS
  • 兼容性:React 19+ 和 Next.js 16+

Installation

安装步骤

bash
npm install motion@12.23.26
bash
npm install motion@12.23.26

Optional for CSS animations

可选:用于CSS动画

npm install tw-animate-css@1.4.0
undefined
npm install tw-animate-css@1.4.0
undefined

1. Centralized Animation Variants

1. 集中式动画变体

Create
src/lib/animations.ts
with reusable variants:
typescript
// Basic fade animations with directional movement
export const fadeInUp = {
  hidden: { opacity: 0, y: 30 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
};

export const fadeInDown = {
  hidden: { opacity: 0, y: -30 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
};

export const fadeInLeft = {
  hidden: { opacity: 0, x: -30 },
  visible: { opacity: 1, x: 0, transition: { duration: 0.6 } }
};

export const fadeInRight = {
  hidden: { opacity: 0, x: 30 },
  visible: { opacity: 1, x: 0, transition: { duration: 0.6 } }
};

export const fadeInScale = {
  hidden: { opacity: 0, scale: 0.8 },
  visible: { opacity: 1, scale: 1, transition: { duration: 0.6 } }
};

// Container for staggered child animations
export const staggerContainer = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: { staggerChildren: 0.1, delayChildren: 0.2 }
  }
};

// Individual items within staggered containers
export const staggerItem = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }
};
创建
src/lib/animations.ts
文件,定义可复用的动画变体:
typescript
// 带有方向移动的基础淡入动画
export const fadeInUp = {
  hidden: { opacity: 0, y: 30 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
};

export const fadeInDown = {
  hidden: { opacity: 0, y: -30 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
};

export const fadeInLeft = {
  hidden: { opacity: 0, x: -30 },
  visible: { opacity: 1, x: 0, transition: { duration: 0.6 } }
};

export const fadeInRight = {
  hidden: { opacity: 0, x: 30 },
  visible: { opacity: 1, x: 0, transition: { duration: 0.6 } }
};

export const fadeInScale = {
  hidden: { opacity: 0, scale: 0.8 },
  visible: { opacity: 1, scale: 1, transition: { duration: 0.6 } }
};

// 用于子元素交错动画的容器
export const staggerContainer = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: { staggerChildren: 0.1, delayChildren: 0.2 }
  }
};

// 交错容器中的单个元素
export const staggerItem = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }
};

2. Implementation Patterns

2. 实现模式

A. Scroll-triggered Animations

A. 滚动触发动画

Standard pattern for content reveals:
tsx
import { motion } from 'motion';
import { fadeInUp } from '@/lib/animations';

<motion.div
  variants={fadeInUp}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
>
  Content here
</motion.div>
内容展示的标准模式:
tsx
import { motion } from 'motion';
import { fadeInUp } from '@/lib/animations';

<motion.div
  variants={fadeInUp}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
>
  内容区域
</motion.div>

B. Staggered Animations

B. 交错动画

For sequential reveals of multiple elements:
tsx
import { motion } from 'motion';
import { staggerContainer, staggerItem } from '@/lib/animations';

<motion.div
  variants={staggerContainer}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
>
  <motion.h1 variants={staggerItem}>Title</motion.h1>
  <motion.p variants={staggerItem}>Subtitle</motion.p>
  <motion.div variants={staggerItem}>CTA Buttons</motion.div>
</motion.div>
用于多个元素的顺序展示:
tsx
import { motion } from 'motion';
import { staggerContainer, staggerItem } from '@/lib/animations';

<motion.div
  variants={staggerContainer}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
>
  <motion.h1 variants={staggerItem}>标题</motion.h1>
  <motion.p variants={staggerItem}>副标题</motion.p>
  <motion.div variants={staggerItem}>CTA按钮</motion.div>
</motion.div>

C. Interactive Animations

C. 交互式动画

For buttons and interactive elements:
tsx
import { motion } from 'motion';

<motion.button
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
  animate={{ y: [0, -8, 0] }}
  transition={{
    y: { duration: 2, repeat: Infinity, ease: "easeInOut" }
  }}
>
  Call to Action
</motion.button>
用于按钮和交互元素:
tsx
import { motion } from 'motion';

<motion.button
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
  animate={{ y: [0, -8, 0] }}
  transition={{
    y: { duration: 2, repeat: Infinity, ease: "easeInOut" }
  }}
>
  行动召唤
</motion.button>

3. Advanced Animation Features

3. 高级动画特性

A. SVG Path Animation

A. SVG路径动画

For connecting lines and decorative elements:
tsx
import { motion } from 'motion';

<motion.svg>
  <motion.path
    d="M 200 100 Q 400 50 600 100 T 1000 100"
    stroke="rgb(var(--primary) / 0.3)"
    strokeDasharray="8 8"
    initial={{ pathLength: 0 }}
    whileInView={{ pathLength: 1 }}
    viewport={{ once: true }}
    transition={{ duration: 2, delay: 0.5 }}
  />
</motion.svg>
用于连接线和装饰元素:
tsx
import { motion } from 'motion';

<motion.svg>
  <motion.path
    d="M 200 100 Q 400 50 600 100 T 1000 100"
    stroke="rgb(var(--primary) / 0.3)"
    strokeDasharray="8 8"
    initial={{ pathLength: 0 }}
    whileInView={{ pathLength: 1 }}
    viewport={{ once: true }}
    transition={{ duration: 2, delay: 0.5 }}
  />
</motion.svg>

B. Hover Interactions with Dynamic Properties

B. 带有动态属性的悬停交互

tsx
import { motion } from 'motion';

<motion.span
  whileHover={{
    scale: 1.2,
    backgroundColor: "rgb(var(--primary) / 0.2)"
  }}
  transition={{ duration: 0.2 }}
>
  Icon
</motion.span>
tsx
import { motion } from 'motion';

<motion.span
  whileHover={{
    scale: 1.2,
    backgroundColor: "rgb(var(--primary) / 0.2)"
  }}
  transition={{ duration: 0.2 }}
>
  图标
</motion.span>

4. CSS Animations for Continuous Effects

4. 用于持续效果的CSS动画

Complement Motion animations with CSS for always-running effects:
css
/* Add to globals.css */
@keyframes float {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-5px); }
}

@keyframes slide-up {
  0% { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}

.animate-float { 
  animation: float 4s ease-in-out infinite; 
}

.animate-slide-up { 
  animation: slide-up 0.4s ease-out forwards; 
  opacity: 0; 
}
用CSS动画补充Motion动画,实现持续运行的效果:
css
/* 添加到globals.css */
@keyframes float {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-5px); }
}

@keyframes slide-up {
  0% { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}

.animate-float { 
  animation: float 4s ease-in-out infinite; 
}

.animate-slide-up { 
  animation: slide-up 0.4s ease-out forwards; 
  opacity: 0; 
}

5. Animation Timing Strategy

5. 动画时序策略

Performance Optimizations

性能优化

  • Use
    viewport={{ once: true }}
    to prevent re-triggers
  • Consistent 0.6s duration for main elements
  • 0.1s stagger delays for sequential reveals
  • 0.2s delay before children start animating
  • 使用
    viewport={{ once: true }}
    防止重复触发
  • 主元素统一使用0.6秒的动画时长
  • 顺序展示的元素使用0.1秒的交错延迟
  • 子元素动画开始前添加0.2秒的延迟

Layered Animation Approach

分层动画方案

  1. Immediate: CSS animations for persistent effects
  2. On Scroll: Motion variants for content reveals
  3. On Interaction: Hover/tap states for interactivity
  4. Background: Subtle floating animations for visual interest
  1. 即时效果:使用CSS动画实现持续效果
  2. 滚动触发:使用Motion变体实现内容展示
  3. 交互触发:悬停/点击状态提供交互反馈
  4. 背景效果:微妙的浮动动画提升视觉吸引力

6. Component Integration Examples

6. 组件集成示例

Hero Section

Hero区块

Two-column layout with opposing slide animations:
tsx
<motion.section className="grid md:grid-cols-2 gap-8">
  <motion.div
    variants={fadeInLeft}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    <h1>Hero Title</h1>
    <p>Hero Description</p>
  </motion.div>
  
  <motion.div
    variants={fadeInRight}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    <img src="/hero-image.jpg" alt="Hero" />
  </motion.div>
</motion.section>
双列布局,使用相反方向的滑动动画:
tsx
<motion.section className="grid md:grid-cols-2 gap-8">
  <motion.div
    variants={fadeInLeft}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    <h1>Hero标题</h1>
    <p>Hero描述</p>
  </motion.div>
  
  <motion.div
    variants={fadeInRight}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    <img src="/hero-image.jpg" alt="Hero" />
  </motion.div>
</motion.section>

Features Grid

功能网格

Staggered item reveals with hover interactions:
tsx
<motion.div 
  variants={staggerContainer}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
  className="grid md:grid-cols-3 gap-6"
>
  {features.map((feature, index) => (
    <motion.div
      key={index}
      variants={staggerItem}
      whileHover={{ y: -5 }}
      className="p-6 bg-white rounded-lg shadow"
    >
      <h3>{feature.title}</h3>
      <p>{feature.description}</p>
    </motion.div>
  ))}
</motion.div>
交错展示的项目,带有悬停交互:
tsx
<motion.div 
  variants={staggerContainer}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
  className="grid md:grid-cols-3 gap-6"
>
  {features.map((feature, index) => (
    <motion.div
      key={index}
      variants={staggerItem}
      whileHover={{ y: -5 }}
      className="p-6 bg-white rounded-lg shadow"
    >
      <h3>{feature.title}</h3>
      <p>{feature.description}</p>
    </motion.div>
  ))}
</motion.div>

Process Steps

流程步骤

Sequential reveals with connecting line animations:
tsx
<motion.div className="relative">
  {/* Connecting line */}
  <motion.div
    className="absolute left-4 top-8 h-full w-0.5 bg-primary/20"
    initial={{ scaleY: 0 }}
    whileInView={{ scaleY: 1 }}
    viewport={{ once: true }}
    transition={{ duration: 1, delay: 0.5 }}
  />
  
  {/* Steps */}
  <motion.div
    variants={staggerContainer}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    {steps.map((step, index) => (
      <motion.div
        key={index}
        variants={staggerItem}
        className="relative pl-12 pb-8"
      >
        <div className="absolute left-0 w-8 h-8 bg-primary rounded-full" />
        <h3>{step.title}</h3>
        <p>{step.description}</p>
      </motion.div>
    ))}
  </motion.div>
</motion.div>
顺序展示的步骤,带有连接线动画:
tsx
<motion.div className="relative">
  {/* 连接线 */}
  <motion.div
    className="absolute left-4 top-8 h-full w-0.5 bg-primary/20"
    initial={{ scaleY: 0 }}
    whileInView={{ scaleY: 1 }}
    viewport={{ once: true }}
    transition={{ duration: 1, delay: 0.5 }}
  />
  
  {/* 步骤 */}
  <motion.div
    variants={staggerContainer}
    initial="hidden"
    whileInView="visible"
    viewport={{ once: true }}
  >
    {steps.map((step, index) => (
      <motion.div
        key={index}
        variants={staggerItem}
        className="relative pl-12 pb-8"
      >
        <div className="absolute left-0 w-8 h-8 bg-primary rounded-full" />
        <h3>{step.title}</h3>
        <p>{step.description}</p>
      </motion.div>
    ))}
  </motion.div>
</motion.div>

CTA Sections

CTA区块

Pulsing buttons with bounce effects:
tsx
<motion.section
  variants={fadeInScale}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
  className="text-center py-16"
>
  <motion.button
    whileHover={{ scale: 1.05 }}
    whileTap={{ scale: 0.95 }}
    animate={{ 
      boxShadow: [
        "0 0 0 0 rgba(59, 130, 246, 0.7)",
        "0 0 0 10px rgba(59, 130, 246, 0)",
      ]
    }}
    transition={{
      boxShadow: { duration: 1.5, repeat: Infinity }
    }}
    className="px-8 py-4 bg-blue-500 text-white rounded-lg"
  >
    Get Started Now
  </motion.button>
</motion.section>
带有脉冲效果的按钮:
tsx
<motion.section
  variants={fadeInScale}
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true }}
  className="text-center py-16"
>
  <motion.button
    whileHover={{ scale: 1.05 }}
    whileTap={{ scale: 0.95 }}
    animate={{ 
      boxShadow: [
        "0 0 0 0 rgba(59, 130, 246, 0.7)",
        "0 0 0 10px rgba(59, 130, 246, 0)",
      ]
    }}
    transition={{
      boxShadow: { duration: 1.5, repeat: Infinity }
    }}
    className="px-8 py-4 bg-blue-500 text-white rounded-lg"
  >
    立即开始
  </motion.button>
</motion.section>

7. Best Practices

7. 最佳实践

Performance Guidelines

性能指南

  • Always use
    viewport={{ once: true }}
    for scroll animations
  • Prefer
    transform
    and
    opacity
    changes over layout properties
  • Use
    will-change: transform
    sparingly and remove after animation
  • Batch animations that occur simultaneously
  • 滚动动画始终使用
    viewport={{ once: true }}
  • 优先使用
    transform
    opacity
    属性变化,而非布局属性
  • 谨慎使用
    will-change: transform
    ,动画结束后移除该属性
  • 批量处理同时发生的动画

Accessibility Considerations

无障碍考虑

  • Respect
    prefers-reduced-motion
    media query
  • Provide fallbacks for users with motion sensitivity
  • Keep animation durations reasonable (< 1s for most interactions)
  • 尊重
    prefers-reduced-motion
    媒体查询
  • 为对动效敏感的用户提供降级方案
  • 保持动画时长合理(大多数交互动画时长<1秒)

Implementation Example with Reduced Motion Support

支持减少动效的实现示例

tsx
import { motion } from 'motion';

const AnimatedComponent = ({ children }) => {
  const prefersReducedMotion = typeof window !== 'undefined' && 
    window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  return (
    <motion.div
      variants={prefersReducedMotion ? {} : fadeInUp}
      initial={prefersReducedMotion ? false : "hidden"}
      whileInView={prefersReducedMotion ? false : "visible"}
      viewport={{ once: true }}
    >
      {children}
    </motion.div>
  );
};
tsx
import { motion } from 'motion';

const AnimatedComponent = ({ children }) => {
  const prefersReducedMotion = typeof window !== 'undefined' && 
    window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  return (
    <motion.div
      variants={prefersReducedMotion ? {} : fadeInUp}
      initial={prefersReducedMotion ? false : "hidden"}
      whileInView={prefersReducedMotion ? false : "visible"}
      viewport={{ once: true }}
    >
      {children}
    </motion.div>
  );
};

8. Package.json Dependencies

8. Package.json 依赖

json
{
  "dependencies": {
    "motion": "^12.23.26"
  },
  "devDependencies": {
    "tw-animate-css": "^1.4.0"
  }
}
json
{
  "dependencies": {
    "motion": "^12.23.26"
  },
  "devDependencies": {
    "tw-animate-css": "^1.4.0"
  }
}

Summary

总结

This animation system provides:
  • Smooth, performant animations that enhance UX without overwhelming
  • Clear separation between scroll-triggered reveals, interactive feedback, and ambient effects
  • Centralized management for consistency across the application
  • Performance optimization through proper timing and viewport controls
  • Accessibility support with reduced motion preferences
The system scales from simple fade-ins to complex orchestrated sequences while maintaining optimal performance in Next.js applications.
本动画系统提供:
  • 流畅、高性能的动画,提升用户体验而不造成干扰
  • 清晰的职责划分,区分滚动触发展示、交互反馈和环境动效
  • 集中式管理,确保应用内动画风格一致
  • 性能优化,通过合理的时序和视口控制实现
  • 无障碍支持,适配减少动效的用户偏好
该系统可从简单的淡入效果扩展到复杂的编排序列,同时在Next.js应用中保持最优性能。