本页出处
设计风格资料库
内容来自 luckymaomi 的 UI 风格库(复刻版),以 MIT 许可 提供。本站镜像收录,仅作学习参考;这一页的原始地址是 原站页面。
← 回到导览访问原站仓库
返回动效库
加载入门

三点弹跳加载

三个圆点依次弹跳的加载指示器,轻量且易于实现。

持续播放1.4s

交互预览

动效定义与代码

{
  "slug": "spinner-dots",
  "name": "三点弹跳加载",
  "nameEn": "Spinner Dots",
  "description": "三个圆点依次弹跳的加载指示器,轻量且易于实现。",
  "descriptionEn": "Three dots bouncing in sequence as a loading indicator. Lightweight and easy to implement.",
  "category": "loading",
  "tags": [
    "loading",
    "spinner",
    "dots",
    "bounce"
  ],
  "trigger": "continuous",
  "difficulty": "beginner",
  "duration": "1.4s",
  "easing": "ease-in-out",
  "cssProperties": [
    "transform",
    "opacity"
  ],
  "isGPUAccelerated": true,
  "previewBg": "light",
  "keywords": [
    "spinner",
    "dots",
    "loading",
    "bounce",
    "indicator",
    "three dots"
  ],
  "useCases": [
    "Button loading state",
    "Chat message typing indicator",
    "Content loading placeholder",
    "Form submission feedback"
  ],
  "relatedAnimations": [
    "skeleton-pulse"
  ],
  "recommendedStyles": [
    "minimalist-flat",
    "soft-ui",
    "fluent-design"
  ],
  "codeSnippets": [
    {
      "label": "CSS Keyframes",
      "language": "css",
      "code": "@keyframes spinner-dot-bounce {\n  0%, 80%, 100% {\n    transform: scale(0);\n    opacity: 0.5;\n  }\n  40% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n.spinner-dots {\n  will-change: transform, opacity;\n  display: inline-flex;\n  gap: 4px;\n}\n\n.spinner-dots span {\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  background-color: currentColor;\n  animation: spinner-dot-bounce 1.4s ease-in-out infinite both;\n}\n\n.spinner-dots span:nth-child(1) { animation-delay: -0.32s; }\n.spinner-dots span:nth-child(2) { animation-delay: -0.16s; }\n.spinner-dots span:nth-child(3) { animation-delay: 0s; }\n\n@media (prefers-reduced-motion: reduce) {\n  .spinner-dots {\n    animation: none;\n  }\n}"
    },
    {
      "label": "Tailwind CSS",
      "language": "css",
      "code": "@keyframes spinner-dot-bounce {\n  0%, 80%, 100% {\n    transform: scale(0);\n    opacity: 0.5;\n  }\n  40% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@utility animate-spinner-dot {\n  will-change: transform, opacity;\n  animation: spinner-dot-bounce 1.4s ease-in-out infinite both;\n}\n\n/* Usage:\n<div class=\"inline-flex gap-1\">\n  <span class=\"w-2 h-2 rounded-full bg-current animate-spinner-dot [animation-delay:-0.32s]\" />\n  <span class=\"w-2 h-2 rounded-full bg-current animate-spinner-dot [animation-delay:-0.16s]\" />\n  <span class=\"w-2 h-2 rounded-full bg-current animate-spinner-dot\" />\n</div>\n*/\n\n@media (prefers-reduced-motion: reduce) {\n  .spinner-dots {\n    animation: none;\n  }\n}"
    },
    {
      "label": "Framer Motion",
      "language": "tsx",
      "code": "import { motion } from \"framer-motion\";\n\n// Tip: disable for users who prefer reduced motion\n// import { useReducedMotion } from \"framer-motion\";\n// const reduced = useReducedMotion();\n// if (reduced) return <div className=\"static-fallback\" />;\n\nconst dots = [0, 1, 2];\n\n<div style={{ display: \"flex\", gap: 4 }}>\n  {dots.map((i) => (\n    <motion.span\n      key={i}\n      animate={{ scale: [0, 1, 0], opacity: [0.5, 1, 0.5] }}\n      transition={{\n        duration: 1.4,\n        repeat: Infinity,\n        delay: i * 0.16,\n        ease: \"easeInOut\",\n      }}\n      style={{ width: 8, height: 8, borderRadius: \"50%\", background: \"currentColor\" }}\n    />\n  ))}\n</div>"
    }
  ]
}