右侧滑出
元素向右侧滑出视口并消失,适合侧面板关闭、抽屉菜单收起等退场效果。
交互预览
动效定义与代码
{
"slug": "slide-out-right",
"name": "右侧滑出",
"nameEn": "Slide Out Right",
"description": "元素向右侧滑出视口并消失,适合侧面板关闭、抽屉菜单收起等退场效果。",
"descriptionEn": "Element slides out to the right and disappears. Perfect for closing side panels, drawers, and split-screen exits.",
"category": "exit",
"tags": [
"slide",
"exit",
"horizontal",
"panel"
],
"trigger": "on-click",
"difficulty": "beginner",
"duration": "400ms",
"easing": "cubic-bezier(0.4, 0, 1, 1)",
"cssProperties": [
"opacity",
"transform"
],
"isGPUAccelerated": true,
"previewBg": "light",
"keywords": [
"slide out",
"right",
"exit",
"panel close",
"drawer",
"dismiss"
],
"useCases": [
"Side panel closing",
"Drawer menu dismiss",
"Card swipe-to-dismiss",
"Page transition exit"
],
"relatedAnimations": [
"slide-in-left",
"slide-in-right",
"fade-out-down"
],
"recommendedStyles": [
"minimalist-flat",
"corporate-clean",
"soft-ui"
],
"codeSnippets": [
{
"label": "CSS Keyframes",
"language": "css",
"code": "@keyframes slide-out-right {\n from {\n opacity: 1;\n transform: translateX(0);\n }\n to {\n opacity: 0;\n transform: translateX(100%);\n }\n}\n\n.slide-out-right {\n --sk-duration: 400ms;\n --sk-delay: 0ms;\n --sk-ease: cubic-bezier(0.4, 0, 1, 1);\n will-change: transform, opacity;\n animation: slide-out-right var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .slide-out-right {\n animation: none;\n opacity: 0;\n transform: none;\n }\n}"
},
{
"label": "Tailwind CSS",
"language": "css",
"code": "@keyframes slide-out-right {\n from {\n opacity: 1;\n transform: translateX(0);\n }\n to {\n opacity: 0;\n transform: translateX(100%);\n }\n}\n\n@utility animate-slide-out-right {\n --sk-duration: 400ms;\n --sk-delay: 0ms;\n --sk-ease: cubic-bezier(0.4, 0, 1, 1);\n will-change: transform, opacity;\n animation: slide-out-right var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .slide-out-right {\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 SlideOutPanel({ children }: { children: ReactNode }) {\n const panelRef = 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 closePanel() {\n const panel = panelRef.current;\n if (!panel || prefersReducedMotion()) return;\n\n const { animate } = await import(\"animejs\");\n if (panelRef.current !== panel) return;\n\n animationRef.current?.cancel();\n resetElement(panel);\n\n animationRef.current = animate(panel, {\n opacity: [1, 0],\n x: [\"0%\", \"100%\"],\n duration: 400,\n ease: \"in(2)\",\n onComplete: () => resetElement(panel),\n });\n }\n\n return (\n <div>\n <button type=\"button\" onClick={() => void closePanel()}>\n Close\n </button>\n <div ref={panelRef} 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, x: 0 }}\n exit={{ opacity: 0, x: \"100%\" }}\n transition={{ duration: 0.4, ease: [0.4, 0, 1, 1] }}\n>\n Content\n</motion.div>"
}
]
}