看得见怎么动的网页动画
前 3 张是 workflow.maysuns.uk 首页「全景图」里的图,由 Python 生成 SVG + 纯 CSS 动画,没有任何图片文件、没有 JavaScript。下面的配方每个都是一小段独立 HTML。
① 由哪些部分组成
怎么动的
- 中间蓝色圆是"核心",用 CSS 的
@keyframes pulse让它在 1 倍和 1.07 倍之间来回缩放(2.4 秒一轮)。 - 中心到各方块的连线是虚线,动画不断改
stroke-dashoffset(0 → -24,1.4 秒循环),虚线的"起点"在移动,看起来像在流动。 - 每个方块是一个
<g class="sat">,用animation-delay错开 0.15 秒依次"弹出"(透明度 0→1,缩放 0.7→1)。 - 方块的位置不是手摆的:用三角函数把 7 个方块均匀放在一个圆上(角度 = i × 360° ÷ 7),所以改数量只改一个数字。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>① 由哪些部分组成</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.ovw h2{border-top:0;margin-top:8px}.ovw .card2{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin:14px 0}
.ovw h3{margin:0 0 6px}.ov{width:100%;height:auto;display:block;color:var(--text)}
.ov .core{animation:pulse 2.4s ease-in-out infinite;transform-origin:center;transform-box:fill-box}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}
.ov .dashline{animation:dash 1.4s linear infinite}@keyframes dash{to{stroke-dashoffset:-24}}
.ov .sat{animation:pop .6s ease both;transform-box:fill-box;transform-origin:center}@keyframes pop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}
.ov .sat:hover rect{opacity:.32}
.ov .runner{offset-path:path('M60 90 L840 90');offset-distance:0%;animation:run 5s linear infinite}@keyframes run{to{offset-distance:100%}}
.ov .orbit{offset-path:circle(135px at 380px 190px);animation:run 6s linear infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@media(prefers-reduced-motion:reduce){.ov *,.can *{animation:none!important}.ov .runner,.ov .orbit{display:none}}
</style></head><body><div class="box">
<svg viewBox="0 0 760 440" class="ov" role="img" aria-label="① 由哪些部分组成"><line x1="380" y1="220" x2="380" y2="55" stroke="#2563eb" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.0s"><rect x="305" y="27" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="305" y="27" width="150" height="56" rx="14" fill="#2563eb" opacity=".14" stroke="#2563eb" stroke-width="2"/><text x="380" y="49" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">CLAUDE.md / Rule</text><text x="380" y="65" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">规矩</text></g><line x1="380" y1="220" x2="545" y2="117" stroke="#7c3aed" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.1s"><rect x="470" y="89" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="470" y="89" width="150" height="56" rx="14" fill="#7c3aed" opacity=".14" stroke="#7c3aed" stroke-width="2"/><text x="545" y="111" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">Memory</text><text x="545" y="127" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">记忆</text></g><line x1="380" y1="220" x2="586" y2="257" stroke="#059669" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.3s"><rect x="511" y="229" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="511" y="229" width="150" height="56" rx="14" fill="#059669" opacity=".14" stroke="#059669" stroke-width="2"/><text x="586" y="251" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">Skill</text><text x="586" y="267" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">做事步骤</text></g><line x1="380" y1="220" x2="472" y2="369" stroke="#d97706" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.4s"><rect x="397" y="341" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="397" y="341" width="150" height="56" rx="14" fill="#d97706" opacity=".14" stroke="#d97706" stroke-width="2"/><text x="472" y="363" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">Command</text><text x="472" y="378" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">一键流程</text></g><line x1="380" y1="220" x2="288" y2="369" stroke="#dc2626" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.6s"><rect x="213" y="341" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="213" y="341" width="150" height="56" rx="14" fill="#dc2626" opacity=".14" stroke="#dc2626" stroke-width="2"/><text x="288" y="363" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">Permission</text><text x="288" y="378" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">安全带</text></g><line x1="380" y1="220" x2="174" y2="257" stroke="#0891b2" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.8s"><rect x="99" y="229" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="99" y="229" width="150" height="56" rx="14" fill="#0891b2" opacity=".14" stroke="#0891b2" stroke-width="2"/><text x="174" y="251" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">MCP</text><text x="174" y="267" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">外接工具</text></g><line x1="380" y1="220" x2="215" y2="117" stroke="#db2777" stroke-width="2.5" stroke-dasharray="6 6" class="dashline" opacity=".7"/><g class="sat" style="animation-delay:0.9s"><rect x="140" y="89" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="140" y="89" width="150" height="56" rx="14" fill="#db2777" opacity=".14" stroke="#db2777" stroke-width="2"/><text x="215" y="111" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">子 Agent / loop</text><text x="215" y="127" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">分身与定时</text></g><circle cx="380" cy="220" r="70" fill="#2563eb" class="core"/><text x="380" y="213" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">AI</text><text x="380" y="233" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">(Claude Code)</text></svg>
</div></body></html>② 怎么运转(小球沿线走)
怎么动的
- 底下那条直线是 SVG 的
<path d="M60 90 L840 90">:从 (60,90) 画到 (840,90)。 - 小球本身是个普通圆
<circle r="7">,关键是 CSS 的offset-path: path('M60 90 L840 90')——告诉浏览器"按这条路线走"。 - 再写
@keyframes run { to { offset-distance: 100% } },把offset-distance从 0% 推到 100%,小球就从起点走到终点(5 秒,线性,无限循环)。 - 要让小球走曲线/回环,只要把 path 换成曲线(
C命令)即可,不用改动画。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>② 怎么运转(小球沿线走)</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.ovw h2{border-top:0;margin-top:8px}.ovw .card2{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin:14px 0}
.ovw h3{margin:0 0 6px}.ov{width:100%;height:auto;display:block;color:var(--text)}
.ov .core{animation:pulse 2.4s ease-in-out infinite;transform-origin:center;transform-box:fill-box}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}
.ov .dashline{animation:dash 1.4s linear infinite}@keyframes dash{to{stroke-dashoffset:-24}}
.ov .sat{animation:pop .6s ease both;transform-box:fill-box;transform-origin:center}@keyframes pop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}
.ov .sat:hover rect{opacity:.32}
.ov .runner{offset-path:path('M60 90 L840 90');offset-distance:0%;animation:run 5s linear infinite}@keyframes run{to{offset-distance:100%}}
.ov .orbit{offset-path:circle(135px at 380px 190px);animation:run 6s linear infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@media(prefers-reduced-motion:reduce){.ov *,.can *{animation:none!important}.ov .runner,.ov .orbit{display:none}}
</style></head><body><div class="box">
<svg viewBox="0 0 900 250" class="ov" role="img" aria-label="② 怎么运转"><path d="M60 90 L840 90" stroke="#94a3b8" stroke-width="3" stroke-dasharray="8 6" class="dashline" fill="none"/><g class="sat" style="animation-delay:0.0s"><rect x="1" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="1" y="55" width="118" height="70" rx="14" fill="#2563eb" opacity=".14" stroke="#2563eb" stroke-width="2"/><circle cx="60" cy="55" r="13" fill="#2563eb"/><text x="60" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">1</text><text x="60" y="96" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">你说一句</text></g><g class="sat" style="animation-delay:0.1s"><rect x="157" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="157" y="55" width="118" height="70" rx="14" fill="#7c3aed" opacity=".14" stroke="#7c3aed" stroke-width="2"/><circle cx="216" cy="55" r="13" fill="#7c3aed"/><text x="216" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">2</text><text x="216" y="88" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">读规矩</text><text x="216" y="104" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">+ 记忆</text></g><g class="sat" style="animation-delay:0.3s"><rect x="313" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="313" y="55" width="118" height="70" rx="14" fill="#059669" opacity=".14" stroke="#059669" stroke-width="2"/><circle cx="372" cy="55" r="13" fill="#059669"/><text x="372" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">3</text><text x="372" y="88" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">选 Skill</text><text x="372" y="104" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">或命令</text></g><g class="sat" style="animation-delay:0.4s"><rect x="469" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="469" y="55" width="118" height="70" rx="14" fill="#d97706" opacity=".14" stroke="#d97706" stroke-width="2"/><circle cx="528" cy="55" r="13" fill="#d97706"/><text x="528" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">4</text><text x="528" y="96" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">动手干活</text></g><g class="sat" style="animation-delay:0.6s"><rect x="625" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="625" y="55" width="118" height="70" rx="14" fill="#dc2626" opacity=".14" stroke="#dc2626" stroke-width="2"/><circle cx="684" cy="55" r="13" fill="#dc2626"/><text x="684" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">5</text><text x="684" y="96" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">权限把关</text></g><g class="sat" style="animation-delay:0.8s"><rect x="781" y="55" width="118" height="70" rx="14" style="fill:var(--panel)"/><rect x="781" y="55" width="118" height="70" rx="14" fill="#0891b2" opacity=".14" stroke="#0891b2" stroke-width="2"/><circle cx="840" cy="55" r="13" fill="#0891b2"/><text x="840" y="60" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">6</text><text x="840" y="88" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">写回结果</text><text x="840" y="104" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">+ 记忆</text></g><path d="M840 125 C840 215 60 215 60 128" fill="none" stroke="#2563eb" stroke-width="3" stroke-dasharray="8 6" class="dashline"/><polygon points="60,128 53,142 67,140" fill="#2563eb"/><text x="450" y="232" text-anchor="middle" font-size="14" font-weight="600" fill="#2563eb">下一轮更懂你</text><circle r="7" fill="#f59e0b" class="runner"/></svg>
</div></body></html>③ 怎么合作(小球绕圈)
怎么动的
- 路线是圆:
offset-path: circle(135px at 380px 190px)(半径 135,圆心 380,190),小球沿圆周跑,6 秒一圈。 - 虚线圆是同样的圆,用
<circle fill="none" stroke-dasharray="8 6">画,同样靠stroke-dashoffset动画流动。 - 5 个方块也是按角度放在一个椭圆上(横向放大 1.5 倍),和图 ① 同一个思路。
- 最后一行
@media (prefers-reduced-motion: reduce)会在用户系统设置了"减少动态效果"时关掉所有动画——这是无障碍的通用做法,别删。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>③ 怎么合作(小球绕圈)</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.ovw h2{border-top:0;margin-top:8px}.ovw .card2{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin:14px 0}
.ovw h3{margin:0 0 6px}.ov{width:100%;height:auto;display:block;color:var(--text)}
.ov .core{animation:pulse 2.4s ease-in-out infinite;transform-origin:center;transform-box:fill-box}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}
.ov .dashline{animation:dash 1.4s linear infinite}@keyframes dash{to{stroke-dashoffset:-24}}
.ov .sat{animation:pop .6s ease both;transform-box:fill-box;transform-origin:center}@keyframes pop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}
.ov .sat:hover rect{opacity:.32}
.ov .runner{offset-path:path('M60 90 L840 90');offset-distance:0%;animation:run 5s linear infinite}@keyframes run{to{offset-distance:100%}}
.ov .orbit{offset-path:circle(135px at 380px 190px);animation:run 6s linear infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
@media(prefers-reduced-motion:reduce){.ov *,.can *{animation:none!important}.ov .runner,.ov .orbit{display:none}}
</style></head><body><div class="box">
<svg viewBox="0 0 760 380" class="ov" role="img" aria-label="③ 怎么和 AI 合作(req / reply)"><circle cx="380" cy="190" r="135" fill="none" stroke="#94a3b8" stroke-width="3" stroke-dasharray="8 6" class="dashline"/><circle r="8" fill="#f59e0b" class="orbit"/><g class="sat" style="animation-delay:0.0s"><rect x="305" y="27" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="305" y="27" width="150" height="56" rx="14" fill="#2563eb" opacity=".14" stroke="#2563eb" stroke-width="2"/><text x="380" y="57" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">你写 req</text></g><g class="sat" style="animation-delay:0.1s"><rect x="498" y="120" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="498" y="120" width="150" height="56" rx="14" fill="#7c3aed" opacity=".14" stroke="#7c3aed" stroke-width="2"/><text x="573" y="150" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">AI 整理成问题</text></g><g class="sat" style="animation-delay:0.3s"><rect x="424" y="271" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="424" y="271" width="150" height="56" rx="14" fill="#059669" opacity=".14" stroke="#059669" stroke-width="2"/><text x="499" y="293" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">AI 做事</text><text x="499" y="309" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">并写 reply</text></g><g class="sat" style="animation-delay:0.4s"><rect x="186" y="271" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="186" y="271" width="150" height="56" rx="14" fill="#d97706" opacity=".14" stroke="#d97706" stroke-width="2"/><text x="261" y="301" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">你确认 ✅</text></g><g class="sat" style="animation-delay:0.6s"><rect x="112" y="120" width="150" height="56" rx="14" style="fill:var(--panel)"/><rect x="112" y="120" width="150" height="56" rx="14" fill="#dc2626" opacity=".14" stroke="#dc2626" stroke-width="2"/><text x="187" y="142" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">归档</text><text x="187" y="158" text-anchor="middle" font-size="13" font-weight="600" fill="currentColor">下一轮</text></g></svg>
</div></body></html>动效配方
流动的虚线
怎么动的
stroke-dasharray把线切成"画 8、空 6"的虚线;动画把stroke-dashoffset一路减小,虚线整体向前滑动。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>流动的虚线</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.flow{animation:flow 1s linear infinite}@keyframes flow{to{stroke-dashoffset:-14}}
</style></head><body><div class="box">
<svg viewBox="0 0 400 60" style="width:100%;max-width:420px"><line x1="10" y1="30" x2="390" y2="30" stroke="#2563eb" stroke-width="4" stroke-dasharray="8 6" class="flow"/></svg>
</div></body></html>沿路径走的小球
怎么动的
offset-path指定路线,offset-distance从 0% 到 100%。路线可以是任意 SVG 路径。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>沿路径走的小球</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.ball{offset-path:path("M20 90 C120 -10 280 -10 380 90");animation:go 3s ease-in-out infinite alternate}@keyframes go{from{offset-distance:0%}to{offset-distance:100%}}
</style></head><body><div class="box">
<svg viewBox="0 0 400 120" style="width:100%;max-width:420px"><path d="M20 90 C120 -10 280 -10 380 90" fill="none" stroke="#94a3b8" stroke-width="3" stroke-dasharray="6 6"/><circle r="9" fill="#f59e0b" class="ball"/></svg>
</div></body></html>呼吸(脉冲)
呼吸
怎么动的
- 用
transform: scale()在 1 和 1.08 之间来回;ease-in-out让两端慢、中间快,像呼吸。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>呼吸(脉冲)</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.pulse{display:grid;place-items:center;width:120px;height:120px;border-radius:50%;background:#2563eb;color:#fff;font-weight:700;animation:pulse 2.4s ease-in-out infinite}@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}
</style></head><body><div class="box">
<div class="pulse">呼吸</div>
</div></body></html>依次弹出
ABCD
怎么动的
- 每张卡片同一个动画,只是
animation-delay不同(0、0.15、0.3 秒),就有了"一个接一个"的效果。both让动画开始前保持透明。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>依次弹出</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.pops{display:flex;gap:10px}.pops span{display:grid;place-items:center;width:64px;height:64px;border-radius:14px;background:#7c3aed;color:#fff;font-weight:700;animation:pop .6s ease both}@keyframes pop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}
</style></head><body><div class="box">
<div class="pops"><span style="animation-delay:0s">A</span><span style="animation-delay:.15s">B</span><span style="animation-delay:.3s">C</span><span style="animation-delay:.45s">D</span></div>
</div></body></html>上下漂浮
🚀
怎么动的
translateY在 0 和 -8px 之间来回,3 秒一轮,适合图标、插画的"活起来"。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>上下漂浮</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.bob{font-size:3rem;display:inline-block;animation:bob 3s ease-in-out infinite}@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
</style></head><body><div class="box">
<div class="bob">🚀</div>
</div></body></html>描边画出来(手写感)
怎么动的
- 先把
stroke-dasharray设成整条线的长度,再把stroke-dashoffset从"整条长度"减到 0——线就像被笔一点点画出来。长度用pathLength="1"统一成 1,不用自己算。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>描边画出来(手写感)</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.draw{stroke-dasharray:1;stroke-dashoffset:1;animation:draw 2.5s ease forwards infinite}@keyframes draw{0%{stroke-dashoffset:1}70%,100%{stroke-dashoffset:0}}
</style></head><body><div class="box">
<svg viewBox="0 0 200 80" style="width:100%;max-width:260px"><path d="M10 60 C40 0 70 0 100 40 S160 80 190 20" fill="none" stroke="#059669" stroke-width="5" stroke-linecap="round" pathLength="1" class="draw"/></svg>
</div></body></html>流光文字
动起来的标题
怎么动的
- 渐变背景比文字宽一倍(
background-size:200%),再平移background-position;background-clip:text让渐变只显示在文字里。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>流光文字</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.shine{margin:0;font-size:2rem;background:linear-gradient(90deg,#2563eb,#db2777,#f59e0b,#2563eb);background-size:200%;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shine 4s linear infinite}@keyframes shine{to{background-position:200% 0}}
</style></head><body><div class="box">
<h2 class="shine">动起来的标题</h2>
</div></body></html>加载转圈
怎么动的
- 一个有一侧彩色的圆环,
rotate0→360° 线性无限旋转。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>加载转圈</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.spin{width:48px;height:48px;border-radius:50%;border:5px solid #cbd5e1;border-top-color:#2563eb;animation:spin .9s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}
</style></head><body><div class="box">
<div class="spin"></div>
</div></body></html>光标闪烁的打字效果
Hello, 你好!
怎么动的
- 宽度用
steps()一格一格增加(不是平滑变宽),末尾的光标用border-right加闪烁动画。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>光标闪烁的打字效果</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.type{display:inline-block;overflow:hidden;white-space:nowrap;border-right:3px solid #14233a;font:700 1.5rem monospace;width:0;animation:typing 3s steps(10) infinite alternate,blink .7s step-end infinite}@keyframes typing{to{width:11ch}}@keyframes blink{50%{border-color:transparent}}
</style></head><body><div class="box">
<div class="type">Hello, 你好!</div>
</div></body></html>悬停抬起 + 微旋转
把鼠标放上来
怎么动的
- 鼠标放上去时
transform改变,配transition就有平滑过渡。这类"交互动效"不用@keyframes。
源码(单文件 HTML,复制后保存成 .html 双击就能打开)
<!doctype html>
<html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>悬停抬起 + 微旋转</title>
<style>
:root{--panel:#fff;--line:#d0d7e2;--text:#14233a;--bg:#f4f7fb}
body{margin:0;padding:24px;background:var(--bg);color:var(--text);font-family:system-ui,"Microsoft YaHei",sans-serif}
.box{max-width:900px;margin:0 auto}
.lift{display:inline-block;padding:18px 24px;border-radius:14px;background:#fff;border:1px solid #d0d7e2;box-shadow:0 2px 6px rgba(0,0,0,.08);transition:transform .2s,box-shadow .2s}.lift:hover{transform:translateY(-6px) rotate(-2deg);box-shadow:0 12px 24px rgba(0,0,0,.15)}
</style></head><body><div class="box">
<div class="lift">把鼠标放上来</div>
</div></body></html>关于 GIF / Flash / Lottie(如实说明)
- Flash 已经不能用了:Adobe 2020 年底停止支持,所有主流浏览器都已移除。想要同样效果,现在用的是 CSS 动画 + SVG(本页)或 Lottie(把设计师做的动画导出成 JSON,网页用小库播放)。
- GIF:好处是到处都能放(邮件、聊天),缺点是体积大、只有 256 色。本页的动画是实时绘制的,放大不糊、体积只有几 KB;要 GIF 需要另外"录屏转换",本页目前没有提供现成 GIF。
- Lottie:适合复杂的插画动画,需要用 After Effects 等工具做,本页暂时没有 Lottie 示例。
- 以上三项只做了"说明",没有假装已经做完。要不要补 GIF 导出或 Lottie,在 reply 里告诉 AI。
所有动画在系统开启"减少动态效果"时会自动停止。