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

缩放消失

元素缩小并淡出,适合弹窗关闭、气泡消失等退场场景。

点击时300ms

交互预览

动效定义与代码

{
  "slug": "scale-out",
  "name": "缩放消失",
  "nameEn": "Scale Out",
  "description": "元素缩小并淡出,适合弹窗关闭、气泡消失等退场场景。",
  "descriptionEn": "Element shrinks and fades out. Ideal for closing modals, dismissing popups and tooltip exits.",
  "category": "exit",
  "tags": [
    "scale",
    "zoom",
    "exit",
    "unmount"
  ],
  "trigger": "on-click",
  "difficulty": "beginner",
  "duration": "300ms",
  "easing": "cubic-bezier(0.4, 0, 1, 1)",
  "cssProperties": [
    "opacity",
    "transform"
  ],
  "isGPUAccelerated": true,
  "previewBg": "light",
  "keywords": [
    "scale out",
    "zoom out",
    "exit",
    "shrink",
    "dismiss",
    "close"
  ],
  "useCases": [
    "Modal/dialog closing",
    "Popup dismissal",
    "Tooltip disappearance",
    "Floating action button collapse"
  ],
  "relatedAnimations": [
    "scale-in",
    "fade-out-down",
    "collapse"
  ],
  "recommendedStyles": [
    "glassmorphism",
    "minimalist-flat",
    "soft-ui"
  ],
  "codeSnippets": [
    {
      "label": "CSS Keyframes",
      "language": "css",
      "code": "@keyframes scale-out {\n  from {\n    opacity: 1;\n    transform: scale(1);\n  }\n  to {\n    opacity: 0;\n    transform: scale(0.85);\n  }\n}\n\n.scale-out {\n  --sk-duration: 300ms;\n  --sk-delay: 0ms;\n  --sk-ease: cubic-bezier(0.4, 0, 1, 1);\n  will-change: transform, opacity;\n  animation: scale-out var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .scale-out {\n    animation: none;\n    opacity: 0;\n    transform: none;\n  }\n}"
    },
    {
      "label": "Tailwind CSS",
      "language": "css",
      "code": "@keyframes scale-out {\n  from {\n    opacity: 1;\n    transform: scale(1);\n  }\n  to {\n    opacity: 0;\n    transform: scale(0.85);\n  }\n}\n\n@utility animate-scale-out {\n  --sk-duration: 300ms;\n  --sk-delay: 0ms;\n  --sk-ease: cubic-bezier(0.4, 0, 1, 1);\n  will-change: transform, opacity;\n  animation: scale-out var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .scale-out {\n    animation: none;\n    opacity: 0;\n    transform: none;\n  }\n}"
    },
    {
      "label": "AnimeJS",
      "language": "tsx",
      "code": "\"use client\";\n\nimport { useEffect, useRef, type ReactNode } from \"react\";\n\ntype AnimeAnimation = {\n  cancel(): unknown;\n};\n\nfunction prefersReducedMotion() {\n  return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\nfunction resetElement(element: HTMLElement) {\n  element.style.opacity = \"\";\n  element.style.transform = \"\";\n}\n\nexport function ScaleOutCard({ children }: { children: ReactNode }) {\n  const cardRef = useRef<HTMLDivElement>(null);\n  const animationRef = useRef<AnimeAnimation | null>(null);\n\n  useEffect(() => {\n    return () => {\n      animationRef.current?.cancel();\n    };\n  }, []);\n\n  async function exitCard() {\n    const card = cardRef.current;\n    if (!card || prefersReducedMotion()) return;\n\n    const { animate } = await import(\"animejs\");\n    if (cardRef.current !== card) return;\n\n    animationRef.current?.cancel();\n    resetElement(card);\n\n    animationRef.current = animate(card, {\n      opacity: [1, 0],\n      scale: [1, 0.85],\n      duration: 300,\n      ease: \"in(2)\",\n      onComplete: () => resetElement(card),\n    });\n  }\n\n  return (\n    <div>\n      <button type=\"button\" onClick={() => void exitCard()}>\n        Dismiss\n      </button>\n      <div ref={cardRef} className=\"will-change-transform\">\n        {children}\n      </div>\n    </div>\n  );\n}"
    },
    {
      "label": "Framer Motion",
      "language": "tsx",
      "code": "import { motion } from \"framer-motion\";\n\n<motion.div\n  initial={{ opacity: 1, scale: 1 }}\n  exit={{ opacity: 0, scale: 0.85 }}\n  transition={{ duration: 0.3, ease: [0.4, 0, 1, 1] }}\n>\n  Content\n</motion.div>"
    }
  ]
}