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

滚动显现

元素进入视口时淡入显现,利用 IntersectionObserver 实现滚动触发。

滚动时600ms

交互预览

动效定义与代码

{
  "slug": "scroll-reveal",
  "name": "滚动显现",
  "nameEn": "Scroll Reveal",
  "description": "元素进入视口时淡入显现,利用 IntersectionObserver 实现滚动触发。",
  "descriptionEn": "Element fades in when entering the viewport, powered by IntersectionObserver for scroll-triggered reveals.",
  "category": "scroll",
  "tags": [
    "scroll",
    "reveal",
    "intersection",
    "viewport"
  ],
  "trigger": "on-scroll",
  "difficulty": "intermediate",
  "duration": "600ms",
  "easing": "cubic-bezier(0.16, 1, 0.3, 1)",
  "cssProperties": [
    "opacity",
    "transform"
  ],
  "isGPUAccelerated": true,
  "previewBg": "light",
  "keywords": [
    "scroll",
    "reveal",
    "viewport",
    "intersection observer",
    "lazy",
    "on-scroll"
  ],
  "useCases": [
    "Landing page sections",
    "Content-heavy pages",
    "Portfolio project reveals",
    "Feature list staggered entrance"
  ],
  "relatedAnimations": [
    "fade-in-up",
    "parallax-float",
    "stagger-children"
  ],
  "recommendedStyles": [
    "full-page-scroll",
    "hero-fullscreen",
    "editorial"
  ],
  "codeSnippets": [
    {
      "label": "CSS Keyframes",
      "language": "css",
      "code": "@keyframes scroll-reveal {\n  from {\n    opacity: 0;\n    transform: translateY(30px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n.scroll-reveal {\n  --sk-duration: 600ms;\n  --sk-delay: 0ms;\n  --sk-ease: cubic-bezier(0.16, 1, 0.3, 1);\n  will-change: transform, opacity;\n  opacity: 0;\n}\n\n.scroll-reveal.is-visible {\n  animation: scroll-reveal var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .scroll-reveal {\n    animation: none;\n    opacity: 1;\n    transform: none;\n  }\n}"
    },
    {
      "label": "Tailwind CSS",
      "language": "tsx",
      "code": "// Hook + Tailwind approach\nimport { useEffect, useRef, useState } from \"react\";\n\nfunction useScrollReveal() {\n  const ref = useRef<HTMLDivElement>(null);\n  const [isVisible, setIsVisible] = useState(false);\n\n  useEffect(() => {\n    const el = ref.current;\n    if (!el) return;\n    const observer = new IntersectionObserver(\n      ([entry]) => {\n        if (entry.isIntersecting) {\n          setIsVisible(true);\n          observer.unobserve(el);\n        }\n      },\n      { threshold: 0.1 }\n    );\n    observer.observe(el);\n    return () => observer.disconnect();\n  }, []);\n\n  return { ref, isVisible };\n}\n\n// Usage:\n// const { ref, isVisible } = useScrollReveal();\n// <div ref={ref}\n//   className={`transition-all duration-600 ease-out\n//     ${isVisible\n//       ? \"opacity-100 translate-y-0\"\n//       : \"opacity-0 translate-y-8\"}`}\n// />"
    },
    {
      "label": "Framer Motion",
      "language": "tsx",
      "code": "import { motion } from \"framer-motion\";\n\n// Tip: respect user's motion preferences\n// import { useReducedMotion } from \"framer-motion\";\n// const reduced = useReducedMotion();\n// Use reduced ? { opacity: 0 } : { opacity: 0, y: 30 } for initial\n\n<motion.div\n  initial={{ opacity: 0, y: 30 }}\n  whileInView={{ opacity: 1, y: 0 }}\n  viewport={{ once: true, margin: \"-10%\" }}\n  transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}\n>\n  Scroll to reveal\n</motion.div>"
    }
  ]
}