文字揭示
文字通过遮罩从下方逐行揭示显现,常用于英雄区标题和关键文案的戏剧性入场。
交互预览
动效定义与代码
{
"slug": "text-reveal",
"name": "文字揭示",
"nameEn": "Text Reveal",
"description": "文字通过遮罩从下方逐行揭示显现,常用于英雄区标题和关键文案的戏剧性入场。",
"descriptionEn": "Text reveals line by line from behind a mask, creating a dramatic entrance for hero titles and key copy.",
"category": "text",
"tags": [
"text",
"reveal",
"mask",
"clip",
"scroll"
],
"trigger": "on-scroll",
"difficulty": "intermediate",
"duration": "800ms",
"easing": "cubic-bezier(0.16, 1, 0.3, 1)",
"cssProperties": [
"clip-path",
"transform",
"opacity"
],
"isGPUAccelerated": true,
"previewBg": "dark",
"keywords": [
"text reveal",
"mask",
"clip path",
"hero text",
"headline animation",
"scroll text"
],
"useCases": [
"Hero section headline entrance",
"Landing page key messaging",
"Section title scroll reveal",
"Award-winning editorial layouts"
],
"relatedAnimations": [
"typewriter",
"text-gradient-flow",
"scroll-reveal"
],
"recommendedStyles": [
"editorial",
"minimalist-flat",
"dark-mode"
],
"codeSnippets": [
{
"label": "CSS Keyframes",
"language": "css",
"code": "@keyframes text-reveal {\n from {\n clip-path: inset(100% 0 0 0);\n transform: translateY(12px);\n opacity: 0;\n }\n to {\n clip-path: inset(0 0 0 0);\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n.text-reveal {\n --sk-duration: 800ms;\n --sk-delay: 0ms;\n --sk-ease: cubic-bezier(0.16, 1, 0.3, 1);\n animation: text-reveal var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n/* Stagger each line */\n.text-reveal:nth-child(2) { --sk-delay: 120ms; }\n.text-reveal:nth-child(3) { --sk-delay: 240ms; }\n\n@media (prefers-reduced-motion: reduce) {\n .text-reveal {\n animation: none;\n clip-path: none;\n opacity: 1;\n transform: none;\n }\n}"
},
{
"label": "Tailwind CSS",
"language": "css",
"code": "@keyframes text-reveal {\n from {\n clip-path: inset(100% 0 0 0);\n transform: translateY(12px);\n opacity: 0;\n }\n to {\n clip-path: inset(0 0 0 0);\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@utility animate-text-reveal {\n --sk-duration: 800ms;\n --sk-delay: 0ms;\n --sk-ease: cubic-bezier(0.16, 1, 0.3, 1);\n animation: text-reveal var(--sk-duration) var(--sk-ease) var(--sk-delay) both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .text-reveal {\n animation: none;\n clip-path: none;\n opacity: 1;\n transform: none;\n }\n}"
},
{
"label": "Framer Motion",
"language": "tsx",
"code": "import { motion } from \"framer-motion\";\n\nconst lineVariants = {\n hidden: {\n clipPath: \"inset(100% 0 0 0)\",\n y: 12,\n opacity: 0,\n },\n visible: (i: number) => ({\n clipPath: \"inset(0 0 0 0)\",\n y: 0,\n opacity: 1,\n transition: {\n duration: 0.8,\n delay: i * 0.12,\n ease: [0.16, 1, 0.3, 1],\n },\n }),\n};\n\n{lines.map((line, i) => (\n <motion.span\n key={i}\n custom={i}\n variants={lineVariants}\n initial=\"hidden\"\n whileInView=\"visible\"\n viewport={{ once: true }}\n className=\"block\"\n >\n {line}\n </motion.span>\n))}"
}
]
}