三点弹跳加载
三个圆点依次弹跳的加载指示器,轻量且易于实现。
交互预览
动效定义与代码
{
"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>"
}
]
}