挺普通,脚都没在脚蹬上,车把悬空的

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f4f2e8">
<title>海风快递 · Pelican on Wheels</title>
<style>
:root {
color-scheme: light;
--paper: #f4f2e8;
--ink: #193f3c;
--muted: #65817a;
--line: #c9d3c8;
--coral: #ef674d;
--mint: #c2e8df;
--sun: #ffd263;
--feather: #fff9e9;
--shade: #8eb9aa;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
background: var(--paper);
color: var(--ink);
font-family: "Avenir Next", "Segoe UI", "Microsoft YaHei", sans-serif;
}
.page {
width: min(1320px, calc(100% - 88px));
min-height: 100svh;
margin: 0 auto;
display: grid;
grid-template-rows: auto 1fr auto;
}
.topbar {
min-height: 102px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
border-bottom: 1px solid var(--line);
}
.identity {
display: flex;
align-items: center;
gap: 15px;
min-width: 0;
}
.seal {
width: 42px;
aspect-ratio: 1;
display: grid;
place-items: center;
flex: 0 0 auto;
border: 1px solid var(--ink);
border-radius: 50%;
color: var(--coral);
font: 700 12px/1 Georgia, serif;
letter-spacing: 0;
transform: rotate(-12deg);
}
.identity-copy { display: grid; gap: 4px; }
h1 {
margin: 0;
font: 600 25px/1.08 Georgia, "Songti SC", serif;
letter-spacing: 0;
}
.eyebrow, .footer-label {
color: var(--muted);
font-size: 10px;
font-weight: 700;
letter-spacing: 1.4px;
line-height: 1.3;
text-transform: uppercase;
}
.controls {
display: flex;
align-items: center;
gap: 8px;
}
.icon-button {
width: 42px;
height: 42px;
display: grid;
place-items: center;
padding: 0;
border: 1px solid var(--line);
border-radius: 50%;
background: transparent;
color: var(--ink);
cursor: pointer;
transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.icon-button:hover {
border-color: var(--ink);
background: var(--ink);
color: var(--paper);
transform: translateY(-1px);
}
.icon-button:focus-visible {
outline: 3px solid var(--coral);
outline-offset: 3px;
}
.icon-button svg { width: 17px; height: 17px; }
.play-glyph { display: none; }
.motion-toggle[aria-pressed="true"] .pause-glyph { display: none; }
.motion-toggle[aria-pressed="true"] .play-glyph { display: block; }
main {
display: grid;
align-content: center;
padding: 28px 0 24px;
}
.artwork {
position: relative;
width: 100%;
overflow: hidden;
background: var(--mint);
outline: 1px solid rgba(25, 63, 60, .18);
outline-offset: -1px;
isolation: isolate;
}
.artwork svg {
display: block;
width: 100%;
height: auto;
}
.footer {
min-height: 58px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
border-top: 1px solid var(--line);
}
.route-note {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.route-mark {
width: 24px;
height: 1px;
flex: 0 0 auto;
background: var(--coral);
}
.route-note strong {
color: var(--ink);
font: 600 12px/1.3 Georgia, "Songti SC", serif;
letter-spacing: 0;
}
.status {
display: flex;
align-items: center;
gap: 8px;
white-space: nowrap;
}
.status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--coral);
box-shadow: 0 0 0 3px rgba(239, 103, 77, .16);
}
.artwork .motion { animation-play-state: running; }
.artwork.is-paused .motion { animation-play-state: paused !important; }
.cloud-drift { animation: cloud-drift 18s ease-in-out infinite alternate; }
.rider-bob { animation: rider-bob 1.5s ease-in-out infinite; transform-box: view-box; transform-origin: 560px 350px; }
.spokes-rear { animation: wheel-turn 2.4s linear infinite; transform-box: view-box; transform-origin: 345px 540px; }
.spokes-front { animation: wheel-turn 2.4s linear infinite; transform-box: view-box; transform-origin: 835px 540px; }
.crank-spin { animation: wheel-turn 1.15s linear infinite; transform-box: view-box; transform-origin: 565px 540px; }
.leg-a { animation: leg-a 1.15s ease-in-out infinite; transform-box: view-box; transform-origin: 520px 393px; }
.leg-b { animation: leg-b 1.15s ease-in-out infinite; transform-box: view-box; transform-origin: 550px 392px; }
.road-flow { animation: road-flow 2.8s linear infinite; }
@keyframes wheel-turn { to { transform: rotate(360deg); } }
@keyframes rider-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@keyframes leg-a { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(10deg); } }
@keyframes leg-b { 0%, 100% { transform: rotate(9deg); } 50% { transform: rotate(-6deg); } }
@keyframes cloud-drift { from { transform: translateX(-8px); } to { transform: translateX(16px); } }
@keyframes road-flow { to { transform: translateX(-220px); } }
@media (max-width: 700px) {
.page { width: calc(100% - 32px); }
.topbar { min-height: 82px; gap: 12px; }
.identity { gap: 10px; }
.seal { width: 34px; font-size: 10px; }
h1 { font-size: 20px; }
.eyebrow { font-size: 8px; letter-spacing: 1px; }
.icon-button { width: 38px; height: 38px; }
main { padding: 18px 0; }
.footer { min-height: 52px; }
.footer-label { font-size: 9px; letter-spacing: .8px; }
}
@media (max-width: 410px) {
.page { width: calc(100% - 24px); }
.topbar { min-height: 74px; }
.seal { width: 30px; }
h1 { font-size: 18px; }
.controls { gap: 5px; }
.icon-button { width: 35px; height: 35px; }
.route-note strong { font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { scroll-behavior: auto !important; }
.artwork .motion { animation-play-state: paused; }
.icon-button { transition: none; }
}
</style>
</head>
<body>
<div class="page">
<header class="topbar">
<div class="identity">
<div class="seal" aria-hidden="true">07</div>
<div class="identity-copy">
<div class="eyebrow">Coastal courier · Route 07</div>
<h1>海风快递</h1>
</div>
</div>
<div class="controls" aria-label="动画控制">
<button class="icon-button motion-toggle" type="button" aria-label="暂停动画" aria-pressed="false" title="暂停动画">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path class="pause-glyph" d="M8 6v12M16 6v12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path class="play-glyph" d="m9 6 9 6-9 6V6Z" fill="currentColor"/>
</svg>
</button>
<button class="icon-button replay-button" type="button" aria-label="重新播放动画" title="重新播放动画">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M20 11a8 8 0 0 0-14.8-3L3 11m0-6v6h6M4 13a8 8 0 0 0 14.8 3L21 13m0 6v-6h-6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</header>
<main>
<div class="artwork" id="artwork">
<svg id="pelican-scene" viewBox="0 0 1200 720" role="img" aria-labelledby="scene-title scene-description" xmlns="http://www.w3.org/2000/svg">
<title id="scene-title">骑自行车的鹈鹕</title>
<desc id="scene-description">一只戴着小帽子的白色鹈鹕骑着珊瑚红自行车,穿过海边的风和阳光。</desc>
<defs>
<pattern id="ground-speckle" width="34" height="26" patternUnits="userSpaceOnUse">
<circle cx="6" cy="8" r="1.5" fill="#d78256" opacity=".5"/>
<circle cx="25" cy="19" r="1" fill="#d78256" opacity=".38"/>
</pattern>
<clipPath id="scene-clip"><rect width="1200" height="720"/></clipPath>
</defs>
<g clip-path="url(#scene-clip)">
<rect width="1200" height="720" fill="#bfe8df"/>
<circle cx="950" cy="144" r="71" fill="#ffd263"/>
<circle cx="950" cy="144" r="91" fill="none" stroke="#f3bf51" stroke-width="2" stroke-dasharray="2 12"/>
<g class="motion cloud-drift" fill="#f8f6e9" opacity=".96">
<path d="M154 172c3-20 20-34 41-34 14 0 27 7 34 19 7-8 17-13 29-13 20 0 37 15 39 35h-143Z"/>
<path d="M827 261c2-15 15-26 31-26 11 0 21 5 27 14 6-7 14-10 23-10 15 0 28 11 30 26H827Z"/>
</g>
<path d="M0 466c154-72 265-55 402-11 120 39 205 31 327-18 154-63 318-68 471-5v187H0Z" fill="#85bba8"/>
<path d="M0 520c157-43 296-16 425 17 147 37 264 22 408-29 144-51 263-46 367-18v230H0Z" fill="#629985"/>
<path d="M0 625c224-18 412-10 596 1 215 13 413-12 604-24v118H0Z" fill="#e9a270"/>
<path d="M0 625c224-18 412-10 596 1 215 13 413-12 604-24v118H0Z" fill="url(#ground-speckle)" opacity=".75"/>
<path d="M0 625c224-18 412-10 596 1 215 13 413-12 604-24" fill="none" stroke="#193f3c" stroke-width="4" opacity=".5"/>
<g fill="#f5f2de" opacity=".55">
<path d="M90 329h112" stroke="#f5f2de" stroke-width="5" stroke-linecap="round"/>
<path d="M1000 378h98" stroke="#f5f2de" stroke-width="5" stroke-linecap="round"/>
<path d="M1019 395h46" stroke="#f5f2de" stroke-width="3" stroke-linecap="round"/>
</g>
<g class="motion road-flow" fill="none" stroke="#f7d7a8" stroke-width="5" stroke-linecap="round" opacity=".9">
<path d="M1060 658h90M1280 658h90M1500 658h90M1720 658h90"/>
</g>
<g aria-hidden="true">
<circle cx="345" cy="540" r="116" fill="#f4f2e8" stroke="#193f3c" stroke-width="16"/>
<circle cx="345" cy="540" r="99" fill="none" stroke="#fff9e9" stroke-width="3"/>
<g class="motion spokes-rear" stroke="#5a8d7e" stroke-width="3">
<path d="M345 441v198M246 540h198M275 470l140 140M415 470 275 610"/>
<path d="m306 445 78 190M440 501 250 579M392 446l-94 188M443 579l-196-78" opacity=".7"/>
</g>
<circle cx="345" cy="540" r="10" fill="#ef674d" stroke="#193f3c" stroke-width="4"/>
<circle cx="835" cy="540" r="116" fill="#f4f2e8" stroke="#193f3c" stroke-width="16"/>
<circle cx="835" cy="540" r="99" fill="none" stroke="#fff9e9" stroke-width="3"/>
<g class="motion spokes-front" stroke="#5a8d7e" stroke-width="3">
<path d="M835 441v198M736 540h198M765 470l140 140M905 470 765 610"/>
<path d="m796 445 78 190M930 501l-190 78M882 446l-94 188M933 579l-196-78" opacity=".7"/>
</g>
<circle cx="835" cy="540" r="10" fill="#ef674d" stroke="#193f3c" stroke-width="4"/>
</g>
<g fill="none" stroke="#ef674d" stroke-linecap="round" stroke-linejoin="round">
<path d="m345 540 123-143 97 143H345l123-143h205l-108 143 108-143 62 130" stroke-width="17"/>
<path d="m466 397 9-53M447 344h61M724 410l-8-53M704 357h51" stroke-width="12"/>
<path d="m460 397 100 143M624 397l-59 143" stroke="#ffad86" stroke-width="4" opacity=".9"/>
</g>
<circle cx="565" cy="540" r="37" fill="none" stroke="#193f3c" stroke-width="8"/>
<g class="motion crank-spin" fill="none" stroke="#193f3c" stroke-linecap="round" stroke-width="9">
<path d="M565 540 592 510M565 540l-27 30"/>
<path d="M592 510h30M538 570h-30" stroke-width="7"/>
</g>
<g class="motion rider-bob">
<g class="motion leg-a" fill="none" stroke="#e69b34" stroke-linecap="round" stroke-linejoin="round">
<path d="M511 389c15 34 28 59 52 79l27 45" stroke-width="17"/>
<path d="M587 511c14-3 24 2 32 12l-21 7-18-8" fill="#e69b34" stroke-width="8"/>
</g>
<g class="motion leg-b" fill="none" stroke="#d8852c" stroke-linecap="round" stroke-linejoin="round">
<path d="M548 388c-10 37-18 63-15 91l17 40" stroke-width="15"/>
<path d="M548 515c13-1 22 5 28 16l-22 4-16-12" fill="#d8852c" stroke-width="8"/>
</g>
<path d="M473 360c9-48 52-77 102-74 46 3 81 35 91 78-26 40-69 62-118 57-37-4-63-25-75-61Z" fill="#fff9e9" stroke="#193f3c" stroke-width="7" stroke-linejoin="round"/>
<path d="M493 352c28-38 83-55 133-24 9 6 18 15 24 26-28 30-69 44-111 38-19-3-35-16-46-40Z" fill="#bed8c9" stroke="#193f3c" stroke-width="5" stroke-linejoin="round"/>
<path d="M507 349c23 6 43 6 61-2M519 365c20 5 36 4 50-2M536 379c16 3 28 1 39-4" fill="none" stroke="#6f9c8b" stroke-width="4" stroke-linecap="round"/>
<path d="M589 331c24-21 31-47 28-69-3-27 9-48 33-57 17-6 38 1 48 18 9 14 8 33-1 47-7 11-16 17-28 20-13 3-18 17-17 35 1 14 8 25 16 38-25 18-58 17-79-3Z" fill="#fff9e9" stroke="#193f3c" stroke-width="7" stroke-linejoin="round"/>
<path d="M612 282c12-16 20-35 17-55-1-10 2-20 8-27" fill="none" stroke="#bed8c9" stroke-width="8" stroke-linecap="round"/>
<path d="M648 202c8-14 20-21 33-18 12 3 19 13 22 25-14-3-28-3-42 0Z" fill="#ef674d" stroke="#193f3c" stroke-width="5" stroke-linejoin="round"/>
<path d="M676 225c34-2 87 6 145 22 8 2 10 8 3 12-43 7-96 7-148-5-10-2-15-12-8-22Z" fill="#f2bd43" stroke="#193f3c" stroke-width="6" stroke-linejoin="round"/>
<path d="M674 251c41 11 93 12 151 8-8 27-31 47-62 52-37 6-66-14-82-35-8-10-11-17-7-25Z" fill="#ed7955" stroke="#193f3c" stroke-width="6" stroke-linejoin="round"/>
<path d="M693 266c32 7 67 8 104 5" fill="none" stroke="#ffd1a0" stroke-width="4" stroke-linecap="round" opacity=".9"/>
<circle cx="673" cy="218" r="5.5" fill="#193f3c"/>
<circle cx="675" cy="216" r="1.6" fill="#fff9e9"/>
<path d="M640 193c-5-11-4-19 1-26M650 189c0-12 4-19 11-23M660 190c4-10 10-15 18-17" fill="none" stroke="#193f3c" stroke-width="5" stroke-linecap="round"/>
<path d="M594 318c32-12 62-3 86 17 20 16 34 27 48 25 13-2 18 7 11 15l-18 3c-19 0-34-15-56-29-19-12-39-12-59-4Z" fill="#fff9e9" stroke="#193f3c" stroke-width="6" stroke-linejoin="round"/>
<path d="M709 359c8 4 16 10 24 12 7 2 11-2 14-6" fill="none" stroke="#bed8c9" stroke-width="5" stroke-linecap="round"/>
</g>
<g fill="#193f3c" opacity=".75">
<circle cx="106" cy="558" r="4"/><circle cx="124" cy="558" r="4"/><circle cx="142" cy="558" r="4"/>
</g>
<path d="M83 578h83" stroke="#193f3c" stroke-width="2" opacity=".4"/>
</g>
</svg>
</div>
</main>
<footer class="footer">
<div class="route-note">
<span class="route-mark" aria-hidden="true"></span>
<strong>早潮专线 · 海岸邮路</strong>
</div>
<div class="status">
<span class="status-dot" aria-hidden="true"></span>
<span class="footer-label" id="motion-status" aria-live="polite">On the move</span>
</div>
</footer>
</div>
<script>
const artwork = document.querySelector('#artwork');
const toggle = document.querySelector('.motion-toggle');
const replay = document.querySelector('.replay-button');
const status = document.querySelector('#motion-status');
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
function setPaused(paused) {
artwork.classList.toggle('is-paused', paused);
toggle.setAttribute('aria-pressed', String(paused));
toggle.setAttribute('aria-label', paused ? '播放动画' : '暂停动画');
toggle.title = paused ? '播放动画' : '暂停动画';
status.textContent = paused ? 'At a standstill' : 'On the move';
}
setPaused(reduceMotion.matches);
toggle.addEventListener('click', () => {
setPaused(toggle.getAttribute('aria-pressed') !== 'true');
});
replay.addEventListener('click', () => {
const animated = artwork.querySelectorAll('.motion');
animated.forEach((element) => { element.style.animation = 'none'; });
void artwork.offsetWidth;
requestAnimationFrame(() => {
animated.forEach((element) => { element.style.removeProperty('animation'); });
});
});
reduceMotion.addEventListener('change', (event) => setPaused(event.matches));
</script>
</body>
</html>