效果演示

文末可一键复制完整代码
源代码
<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>洞口跳跃</title><scriptsrc="https://unpkg.com/gsap@3/dist/gsap.min.js"></script><scriptsrc="https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js"></script><scriptsrc="https://unpkg.com/gsap@3/dist/GSDevTools.min.js"></script><style>@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap'); * { box-sizing: border-box; } body { min-height: 100vh; display: flex; justify-content: center; align-items: center; color: #fff; background-color: #222; font-family: "Bricolage Grotesque", sans-serif; } .container { border-radius: 30px; width: 400px; height: 300px; position: relative; --bg-dark: #ffc762; --bg-light: #ffe9a4; background-image: linear-gradient(135deg, var(--bg-light) 25%, transparent 25%), linear-gradient(225deg, var(--bg-light) 25%, transparent 25%), linear-gradient(45deg, var(--bg-light) 25%, transparent 25%), linear-gradient(315deg, var(--bg-light) 25%, var(--bg-dark) 25%); background-position: 15px0, 15px0, 00, 00; background-size: 30px30px; background-repeat: repeat; --top-space: calc(300px * 0.7); --hole-width: 150px; --hole-height: 20px; } .inner-box { position: absolute; top: 3px; left: 0; right: 0; width: 80%; height: calc(var(--top-space) + var(--hole-height) / 2); margin: auto; border-radius: 50%; overflow: hidden; } .hole { position: absolute; top: var(--top-space); left: 0; right: 0; margin: auto; width: var(--hole-width); height: var(--hole-height); background-color: #000d; border-radius: 50%; } .shadow { position: absolute; top: var(--top-space); left: 0; right: 0; margin: auto; width: var(--hole-width); height: var(--hole-height); background-image: radial-gradient(#0008, transparent 75%); border-radius: 50%; opacity: 0; } .emoji { position: absolute; bottom: 0; left: 0; right: 0; margin: auto; width: fit-content; font-size: 80px; }</style></head><body><divclass="container"><divclass="hole"></div><divclass="shadow"></div><divclass="inner-box"><divclass="emoji">🎃</div></div></div><script> (() => { gsap.registerPlugin(GSDevTools); const tl = gsap.timeline({ repeat: 1, yoyo: true, repeatDelay: 0.5, }); tl.from('.hole', { scale: 0, repeat: 1, yoyo: true, }) .fromTo('.emoji', { y: 140, scaleY: 2 }, { y: -120, scaleY: 1 }, 0.2) .to('.emoji', { y: 10, ease: 'power1.in' }, '>') .to( '.emoji', { scaleY: 0.8, scaleX: 1.2, transformOrigin: 'center bottom', repeat: 1, yoyo: true, duration: 0.2 }) .to('.shadow', { opacity: 1, duration: 0.2 }, 0.7) .to('.shadow', { scaleX: 0.7, ease: 'power1.in' }, '>') })();</script></body></html>实现思路拆分
洞口跳跃是怎么画出来的?
洞口跳跃(gsap hole jumper animation)用 GSAP 时间轴驱动 🎃 从洞口弹出、拉伸、落地弹跳,洞口与阴影同步缩放,形成卡通式 jump 动画。
说白了就三件事
HTML: .container棋盘格背景 + 椭圆.hole+.shadow+.inner-box裁剪入口内的.emoji。CSS:CSS 变量定洞口位置与尺寸; inner-box上半圆overflow: hidden形成「探出」入口。JavaScript:GSAP timelinerepeat + yoyo,串联 hole 缩放、emoji 位移/挤压、shadow 显隐与缩放。
改节奏动 timeline 的 repeatDelay 与各 tween duration,改洞口动 --hole-width / --top-space。
颜色为啥长这样
背景:深灰 #222页面,容器暖黄棋盘#ffc762/#ffe9a4洞口:半透明黑 #000d椭圆阴影:径向渐变 #0008→ transparent主体:🎃 emoji 80px 整体万圣节暖色调、卡通弹性
动起来是啥感觉
循环播放:洞口出现 → 南瓜从下方弹起 → 越过洞口 → 落回 → 挤压弹跳 → 倒放 yoyo。
洞口 scale: 0 → 1先展开emoji 从 y: 140, scaleY: 2拉伸弹出到y: -120落至 y: 10后scaleY/X挤压弹跳shadow 随跳跃显隐并 scaleX收窄repeat: 1, yoyo: true往返循环,间隔 0.5s
怎么一层层画出来
场景结构
.container:400×300 圆角卡片,斜纹棋盘 background。.inner-box:顶部 70% 处椭圆裁剪区,emoji 从底部向上探出。.hole+.shadow:同一位置叠放,shadow 用 radial-gradient。
GSAP 时间轴
tl.from('.hole', { scale: 0, repeat: 1, yoyo })洞口呼吸。.fromTo('.emoji', ...)拉伸上升,与 hole 略错开 0.2s。.to('.emoji', { y: 10, ease: 'power1.in' })落地。scaleY/X yoyo 挤压弹跳;shadow opacity + scaleX 配合落地。
源码获取

夜雨聆风