Way Farer
aadmin2026-09-12 发布Site模板0 阅读

Way Farer

类型:Site模板 · 分类:未分类 · 收录:2026-09-12 14:58:07 · 源码:会员可见

[hidecontent type="vip1"]
Build a complete, single-file `index.html` hero section for a travel-booking site called
"wayfarer". No build step, no frameworks, no local assets — everything inline in one file
(one <style> block in <head>, one <script> before </body>). Must be fully mobile responsive.

════════════════════════════════════════════════════════════════════════
1. FONTS
════════════════════════════════════════════════════════════════════════
Load from Google Fonts with preconnect to fonts.googleapis.com and fonts.gstatic.com
(crossorigin):
https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap

- "Playfair Display" (serif) — used ONLY for headline line 1 and the light part of the card
  title. Fallback: Georgia, serif.
- "Plus Jakarta Sans" — everything else. Body fallback stack:
  system-ui, -apple-system, "Segoe UI", Roboto, sans-serif.

════════════════════════════════════════════════════════════════════════
2. DESIGN TOKENS (:root custom properties)
════════════════════════════════════════════════════════════════════════
--ink:#33251f;  --ink-soft:#4a3a33;  --muted:#8d8279;  --line:#eae5df;
--orange:#ee5b3f;  --orange-dark:#e04b2e;  --white:#fff;  --sky:#cfe7e6;
--shell:1240px;  --shell-wide:1420px;
--display: clamp(2.6rem, 4.7vw, 5.6rem);
--ease: cubic-bezier(.22,1,.36,1);
--ease-sheet: cubic-bezier(.76,0,.24,1);
--radius-card:22px;  --radius-field:13px;

Base resets: border-box on *,::before,::after; html{-webkit-text-size-adjust:100%};
body{margin:0; font-family Plus Jakarta Sans; color:var(--ink); background:var(--sky);
overflow-x:hidden}; body.nav-open{overflow:hidden}; img,svg,video{display:block;max-width:100%};
button{font:inherit;color:inherit;border:0;background:none;cursor:pointer};
a{color:inherit;text-decoration:none}

════════════════════════════════════════════════════════════════════════
3. BACKGROUND VIDEO (use these exact URLs — do not substitute)
════════════════════════════════════════════════════════════════════════
<video class="bg" autoplay muted loop playsinline preload="auto" poster="POSTER">
  <source src="MP4" type="video/mp4" />
</video>

MP4 (src):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260908_124430_abdf16a0-ba4f-4570-8e96-f7ba8dec9f3f.mp4

POSTER (escape every & as & inside the attribute):
https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260908_121950_627ff478-ebe1-487c-b160-24e86434aae2.png&w=1920&q=85

The video is a flat-vector spring travel illustration: pastel sky, ocean bay, pine trees,
meadow with wildflowers, a walking couple, a cyclist, and a picnic — soft mint/cream palette.

════════════════════════════════════════════════════════════════════════
4. STRUCTURE
════════════════════════════════════════════════════════════════════════
<div class="stage">            → position:relative; min-height:100vh then 100svh; flex column;
                                 overflow:hidden. DO NOT add isolation:isolate (see §9).
  <video class="bg">           → position:absolute; inset:0; z-index:0; width/height 100%;
                                 object-fit:cover; object-position:center 62%
  <div class="bg-wash">        → position:absolute; inset:0; z-index:1; pointer-events:none
  <header class="header">      → position:relative; z-index:60; padding:26px 40px
  <main class="hero">          → position:relative; z-index:10; flex:1; padding:0 40px 16vh;
                                 display:flex; align-items:center
</div>
<div class="sheet-wrap" id="mobile-sheet">   → position:fixed; inset:0; z-index:50
<script>

.bg-wash background (two stacked gradients, desktop):
  linear-gradient(180deg, rgba(255,253,248,.55) 0%, rgba(255,253,248,.16) 28%, rgba(255,253,248,0) 52%),
  radial-gradient(120% 78% at 22% 34%, rgba(255,252,246,.55) 0%, rgba(255,252,246,0) 60%)

════════════════════════════════════════════════════════════════════════
5. HEADER
════════════════════════════════════════════════════════════════════════
.header-inner: max-width:var(--shell-wide); margin:0 auto; display:flex;
align-items:center; gap:28px

LEFT — brand link, aria-label="wayfarer home":
  Inline SVG "mark" (viewBox 0 0 32 32, fill none, class="mark", 28x28), an 8-spoke
  asterisk star drawn as 4 crossed strokes, g stroke=currentColor stroke-width="3.1"
  stroke-linecap="round":
    M16 3.2V28.8   |   M3.2 16H28.8   |   M6.9 6.9L25.1 25.1   |   M25.1 6.9L6.9 25.1
  Then <span>wayfarer</span>
  .brand: display:flex; gap:11px; font-size:1.62rem; font-weight:700;
  letter-spacing:-.035em; flex:0 0 auto
  .brand .mark: transition:transform .6s var(--ease); on .brand:hover → rotate(90deg)

CENTER — <nav class="nav" aria-label="Primary"> with margin:0 auto,
gap:clamp(18px,2.6vw,46px). Four links, exact text in order:
  Voyages · Advice · Attractions · Bookings
  Link style: font-size:1.02rem; font-weight:500; color:var(--ink-soft); padding:6px 2px
  Hover: color→var(--ink), plus an ::after underline (height:2px; border-radius:2px;
  background:var(--ink); left:0;right:0;bottom:0) that animates scaleX(0)→scaleX(1) with
  transform-origin flipping right→left, transition .45s var(--ease)

RIGHT — .header-actions (display:flex; gap:14px; flex:0 0 auto):
  a) <a class="host"> text: "Add Your Home" — same size/weight as nav links;
     hover: color→ink and translateY(-1px)
  b) .icon-btn globe, aria-label="Switch Language" — SVG viewBox 0 0 24 24, fill none,
     stroke currentColor, stroke-width 1.7: circle cx12 cy12 r9; path M3.2 9.4h17.6
     M3.2 14.6h17.6; ellipse cx12 cy12 rx4 ry9
  c) .icon-btn 2x2 dots, aria-label="View Apps Menu" — fill currentColor, four circles
     r=2.1 at (9,8) (15,8) (9,16) (15,16)
  d) .burger button id="burger" aria-label="Show Menu" aria-expanded="false"
     aria-controls="mobile-sheet", containing three empty <span> elements

  .icon-btn: 46x46; border-radius:50%; background:#fff; display:grid; place-items:center;
  box-shadow:0 2px 10px rgba(51,37,31,.09); svg 21x21;
  hover → translateY(-3px) + box-shadow:0 10px 22px rgba(51,37,31,.16);
  transition:transform .38s var(--ease), box-shadow .38s var(--ease)

  .burger: display:none by default; 46x46 circle, white, same shadow;
  position:relative; z-index:60.
  Bars: position:absolute; left:50%; top:50%; width:19px; height:2px; border-radius:2px;
  background:var(--ink); transition:transform .55s var(--ease), opacity .3s ease,
  width .45s var(--ease)
    span1 → translate(-50%, calc(-50% - 5.5px))
    span2 → translate(-50%,-50%); width:13px
    span3 → translate(-50%, calc(-50% + 5.5px))
  When body.nav-open (morph into an X):
    span1 → translate(-50%,-50%) rotate(45deg)
    span2 → opacity:0; translate(-50%,-50%) scaleX(.2)
    span3 → translate(-50%,-50%) rotate(-45deg)

════════════════════════════════════════════════════════════════════════
6. HERO (two-column grid)
════════════════════════════════════════════════════════════════════════
.hero-inner: max-width:var(--shell); margin:0 auto; width:100%; display:grid;
grid-template-columns: minmax(0,1fr) 480px; gap:clamp(32px,5vw,90px); align-items:center

LEFT COLUMN (.hero-copy)
  <h1 class="headline"> line-height:1.02; letter-spacing:-.02em; margin:0
  Two lines, each wrapped as: <span class="line line-N"><span>TEXT</span></span>
  where .line{display:block; overflow:hidden; padding-bottom:.06em} and
  .line > span{display:block}  ← the overflow:hidden gives a mask-reveal feel.
    Line 1 text: "Wander Onward"
      → Playfair Display, weight 400, font-size:var(--display), letter-spacing:-.012em
    Line 2 text: "Toward Spring"
      → Plus Jakarta Sans weight 800, font-size:calc(var(--display) * .855),
        letter-spacing:-.032em
  <p class="hero-sub"> margin:clamp(16px,1.7vw,24px) 0 0; max-width:34ch;
  font-size:clamp(1rem,1.06vw,1.2rem); line-height:1.55; color:var(--ink-soft)
    Exact text: "Discover flowering cities, crisp horizons, and wondrous new places waiting to be explored."
  <a class="cta"> exact text: "Uncover Our Destinations"
    inline-flex centered; margin-top:clamp(24px,2.6vw,38px); padding:1.32em 2.1em;
    border-radius:15px; background:#fff; font-size:clamp(.95rem,.92vw,1.06rem);
    font-weight:700; letter-spacing:-.01em; box-shadow:0 4px 18px rgba(51,37,31,.1);
    hover → translateY(-4px) + 0 16px 32px rgba(51,37,31,.18); active → translateY(-1px);
    transition:transform .4s var(--ease), box-shadow .4s var(--ease)

RIGHT COLUMN (.card) — white search panel
  background:#fff; border-radius:var(--radius-card); padding:clamp(22px,1.9vw,30px);
  box-shadow:0 24px 60px -22px rgba(51,37,31,.28), 0 3px 10px rgba(51,37,31,.05)

  <h2 class="card-title">So where <b>are you headed?</b></h2>
    Base: Playfair Display 400, font-size:clamp(1.32rem,1.42vw,1.62rem),
    letter-spacing:-.005em, line-height:1.25, margin:0
    The <b>: Plus Jakarta Sans 800, letter-spacing:-.028em
  <p class="card-desc"> margin:.6em 0 clamp(16px,1.4vw,20px);
    font-size:clamp(.9rem,.85vw,.98rem); line-height:1.5; color:var(--muted)
    Exact text: "Discover flats, residences, and quirky stays for every type of tour."

  <div class="field-stack"> display:grid; gap:12px — contains 3 rows:

  ROW 1 — full-width <label class="field">, orange filled map-pin SVG, then
    .field-label "Place?" and <input placeholder="Choose Destinations" aria-label="Place?">
    Pin path (fill currentColor, viewBox 0 0 24 24):
      M12 2.2a7.3 7.3 0 0 0-7.3 7.3c0 5.3 6.5 11.6 6.8 11.9a.7.7 0 0 0 1 0c.3-.3 6.8-6.6 6.8-11.9A7.3 7.3 0 0 0 12 2.2Zm0 10a2.9 2.9 0 1 1 0-5.8 2.9 2.9 0 0 1 0 5.8Z

  ROW 2 — <div class="field-split"> = ONE bordered rounded box, display:grid
    grid-template-columns:1fr 1fr; overflow:hidden; holding two <label class="field">
    that have their own border/radius/shadow removed (padding:14px 16px) and are
    separated by `.field-split .field + .field{border-left:1px solid var(--line)}`
      Left  → calendar SVG, label "Days?", placeholder "Set Dates", aria-label="Days?"
        rect x3 y4.6 w18 h16.4 rx3.2 fill=currentColor opacity=.16
        same rect stroked, stroke-width 1.7
        path M3 9.7h18 (sw 1.7); path M8 2.6v3.6M16 2.6v3.6 (sw 1.9, round caps)
        three r=1.15 filled circles at cx 8.2 / 12 / 15.8, cy 14.4
      Right → guests SVG, label "Pax?", placeholder "Add People", aria-label="Pax?"
        circle cx8.6 cy8.2 r3.5; circle cx16.4 cy9 r2.8 opacity=.68
        path M2.4 18.4c0-3.2 2.8-5.1 6.2-5.1s6.2 1.9 6.2 5.1c0 .8-.5 1.2-1.3 1.2H3.7c-.8 0-1.3-.4-1.3-1.2Z
        path M16.5 13.5c2.9 0 5.1 1.6 5.1 4.3 0 .9-.5 1.3-1.3 1.3h-3.6c.3-.5.4-1 .4-1.6 0-1.6-.6-3-1.7-4Z opacity=.68

  ROW 3 — <button class="search-btn" type="button">: magnifier SVG + <span>Browse</span>

  .field: display:flex; align-items:center; gap:14px; border:1px solid var(--line);
    border-radius:var(--radius-field); padding:14px 18px; min-height:70px; background:#fff;
    transition:border-color .35s ease, box-shadow .35s ease, transform .35s var(--ease)
  .field:hover / :focus-within AND .field-split:hover / :focus-within →
    border-color:#d8cec3; box-shadow:0 8px 20px -10px rgba(51,37,31,.24); translateY(-2px)
  .field-icon: 24x24; flex:0 0 auto; color:var(--orange)   ← all three icons are orange
  .field-body: min-width:0; flex:1
  .field-label: display:block; font-size:.94rem; font-weight:700; letter-spacing:-.015em;
    line-height:1.3
  .field-input: display:block; width:100%; border:0; outline:0; padding:2px 0 0;
    font:inherit; font-size:.92rem; color:var(--ink); background:transparent;
    ::placeholder color:var(--muted)

  .search-btn: position:relative; flex centered; width:100%; min-height:70px;
    border-radius:var(--radius-field); background:var(--orange); color:#fff;
    font-size:1.02rem; font-weight:700; letter-spacing:-.01em; overflow:hidden
    Magnifier SVG is position:absolute; left:30px; 24x24 (fill none, stroke currentColor,
    stroke-width 2.1, round caps: circle cx10.8 cy10.8 r6.6; path "M15.8 15.8 21 21")
    while the word "Browse" stays centered in the button.
    ::before sheen: inset:0; background:linear-gradient(100deg,transparent 20%,
    rgba(255,255,255,.28) 50%,transparent 80%); transform:translateX(-120%);
    transition:transform .9s var(--ease); on hover → translateX(120%)
    hover → background:var(--orange-dark); translateY(-3px);
    box-shadow:0 16px 30px -12px rgba(238,91,63,.7);  active → translateY(-1px)

════════════════════════════════════════════════════════════════════════
7. STAGGERED ENTRANCE ANIMATIONS
════════════════════════════════════════════════════════════════════════
Three keyframes, driven by a per-element `--d` delay set inline as style="--d:.52s":

@keyframes rise { from{opacity:0; transform:translate3d(0,26px,0); filter:blur(7px)}
                  to  {opacity:1; transform:none; filter:blur(0)} }
@keyframes drop { from{opacity:0; transform:translate3d(0,-16px,0)} to{opacity:1; transform:none} }
@keyframes pop  { from{opacity:0; transform:translate3d(0,34px,0) scale(.965); filter:blur(9px)}
                  to  {opacity:1; transform:none; filter:blur(0)} }

.anim-rise{ animation:rise .95s var(--ease) both; animation-delay:var(--d,0s) }
.anim-drop{ animation:drop .8s  var(--ease) both; animation-delay:var(--d,0s) }
.anim-pop { animation:pop 1.05s var(--ease) both; animation-delay:var(--d,0s) }

EXACT delays (header drops down, hero rises up, card pops):
  brand .12s | burger .30s | nav: Voyages .22s, Advice .29s, Attractions .36s,
  Bookings .43s | "Add Your Home" .50s | globe .57s | apps .64s      ← all anim-drop
  headline line 1 .52s | line 2 .64s | hero-sub .78s | cta .90s      ← all anim-rise
  card .62s (anim-pop) | card-title .86s | card-desc .94s |
  Place field 1.02s | field-split 1.10s | search-btn 1.18s           ← all anim-rise

Background video ambience:
  .bg starts opacity:0; transform:scale(1.08) and runs
  animation: bgIn 2.4s var(--ease) .05s forwards, bgDrift 34s ease-in-out 2.4s infinite alternate;
  @keyframes bgIn{ to{opacity:1; transform:scale(1.02)} }
  @keyframes bgDrift{ from{transform:scale(1.02)} to{transform:scale(1.09)} }
  .bg-wash starts opacity:0 with animation: washIn 1.6s ease .5s forwards;
  @keyframes washIn{ to{opacity:1} }

Add a prefers-reduced-motion:reduce block that forces animation-duration:.001ms,
animation-delay:0s, transition-duration:.01ms, transition-delay:0s on *,::before,::after
(all !important) and resets .bg to opacity:1; transform:none.

════════════════════════════════════════════════════════════════════════
8. MOBILE MENU SHEET (premium slide-down)
════════════════════════════════════════════════════════════════════════
Markup lives OUTSIDE .stage, as a direct child of <body>:
<div class="sheet-wrap" id="mobile-sheet">
  <div class="sheet-scrim" data-close></div>
  <nav class="sheet" aria-label="Mobile">
    <div class="sheet-nav">   ← 4 links, each: TEXT + <span>↗</span> (↗ arrow),
                                 every link has data-close
      Voyages · Advice · Attractions · Bookings
    </div>
    <div class="sheet-foot">
      <a class="sheet-host" data-close>Add Your Home</a>
      + the same globe .icon-btn (aria-label="Switch Language")
      + the same 2x2-dots .icon-btn (aria-label="View Apps Menu")
    </div>
  </nav>
</div>

.sheet-wrap: position:fixed; inset:0; z-index:50; opacity:0; visibility:hidden;
  transition:opacity .5s ease, visibility 0s linear .5s
body.nav-open .sheet-wrap: opacity:1; visibility:visible;
  transition:opacity .45s ease, visibility 0s
.sheet-scrim: position:absolute; inset:0; background:rgba(51,37,31,.32);
  backdrop-filter:blur(6px) (+ -webkit- prefix)
.sheet: position:absolute; top/left/right:0; background:#fffdfa;
  border-radius:0 0 30px 30px; padding:104px 26px 34px;
  box-shadow:0 30px 70px -20px rgba(51,37,31,.4);
  transform:translateY(-101%); transition:transform .72s var(--ease-sheet);
  max-height:100vh then 100svh; overflow-y:auto
body.nav-open .sheet → transform:translateY(0)
  (the 104px top padding leaves the logo + X button visible above the links)

.sheet-nav a: display:flex; justify-content:space-between; align-items:center;
  padding:17px 4px; font-size:1.28rem; font-weight:600; letter-spacing:-.02em;
  border-bottom:1px solid var(--line); :last-child border-bottom:0;
  starts opacity:0; transform:translateY(18px);
  transition:opacity .5s ease, transform .6s var(--ease), color .25s ease
  a span (the arrow): color:var(--muted); font-size:1rem;
  transition:transform .45s var(--ease); on a:hover → translateX(5px);
  a:active → color:var(--orange)
Staggered open (delays apply only while body.nav-open, so closing snaps back fast):
  nth-child(1) .20s | (2) .27s | (3) .34s | (4) .41s
.sheet-foot: display:flex; align-items:center; gap:12px; margin-top:26px;
  same opacity/translateY(18px) start, transition-delay .50s when open
.sheet-foot .icon-btn{ box-shadow:0 2px 10px rgba(51,37,31,.12); flex:0 0 auto }
.sheet-host: flex:1; inline-flex centered; padding:15px 20px; border-radius:13px;
  background:var(--ink); color:#fffdfa; font-weight:700; font-size:1rem

════════════════════════════════════════════════════════════════════════
9. Z-INDEX / STACKING — CRITICAL, GET THIS RIGHT
════════════════════════════════════════════════════════════════════════
All of these live in the ROOT stacking context. Do NOT put isolation:isolate on .stage
and do NOT give .bg or .bg-wash a negative z-index (a negative z-index there makes the
video disappear behind the body background once .stage is not a stacking context).
Correct order:
  .bg 0  <  .bg-wash 1  <  .hero 10  <  .sheet-wrap 50  <  .header 60
The header MUST outrank the sheet (60 > 50) so the hamburger stays clickable on top of
the open sheet and visibly morphs into the X. .burger itself also carries z-index:60.

════════════════════════════════════════════════════════════════════════
10. RESPONSIVE BREAKPOINTS
════════════════════════════════════════════════════════════════════════
@media (max-width:1180px)
  .hero-inner grid-template-columns: minmax(0,1fr) 420px
  .header padding:22px 28px;  .hero padding:0 28px 12vh

@media (max-width:980px)   ← mobile nav kicks in here
  :root{ --display: clamp(2.7rem, 8.4vw, 4.2rem) }
  hide .nav, .header-actions .host, .header-actions .icon-btn (display:none)
  .burger{ display:block }; .header-inner{ justify-content:space-between };
  .header-actions{ margin-left:auto }
  .hero{ padding:clamp(18px,4vh,44px) 24px clamp(48px,10vh,90px); align-items:flex-start }
  .hero-inner{ grid-template-columns:minmax(0,1fr); gap:34px; max-width:560px }
  .hero-sub{ max-width:46ch }
  .bg{ object-position:center 58% }
  .bg-wash{ background:linear-gradient(180deg, rgba(255,253,248,.72) 0%,
    rgba(255,253,248,.42) 34%, rgba(255,253,248,.1) 60%, rgba(255,253,248,0) 78%) }

@media (max-width:640px)
  .header padding:18px; .brand font-size:1.42rem; .brand .mark 25x25
  .hero padding:6px 18px 46px; .hero-inner gap:28px
  .cta{ width:100%; padding:1.25em 1.6em }
  .card{ padding:20px; border-radius:20px }
  .field{ min-height:64px; padding:12px 15px; gap:12px }
  .field-split .field{ padding:12px 13px }; .field-icon 22x22
  .search-btn{ min-height:64px }; .search-btn svg{ left:22px; width:22px; height:22px }
  .sheet{ padding:96px 20px 30px; border-radius:0 0 26px 26px }

@media (max-width:336px)   ← deliberately low so 360/375/390px phones KEEP Days?+Pax?
                             side by side exactly like the desktop layout
  .field-split{ grid-template-columns:1fr }
  .field-split .field + .field{ border-left:0; border-top:1px solid var(--line) }
  .field-label{ font-size:.9rem }

════════════════════════════════════════════════════════════════════════
11. JAVASCRIPT (vanilla, wrapped in an IIFE)
════════════════════════════════════════════════════════════════════════
- setMenu(open): toggles `nav-open` on <body>, sets burger aria-expanded to "true"/"false",
  and sets burger aria-label to "Hide Panel" when open / "Show Menu" when closed.
- Clicking #burger toggles the menu.
- Clicking ANY [data-close] element (scrim, each sheet link, the sheet host button)
  closes it.
- Escape key closes it.
- window resize > 980px force-closes it.
- Autoplay nudge: grab .bg, call vid.play() and swallow the rejected promise with
  .catch(function(){}); re-call it on document 'visibilitychange' when not hidden.

════════════════════════════════════════════════════════════════════════
12. DOCUMENT HEAD
════════════════════════════════════════════════════════════════════════
<html lang="en">, charset UTF-8,
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>wayfarer — Wander Onward Toward Spring</title>   (real em dash)

════════════════════════════════════════════════════════════════════════
13. OVERALL LOOK
════════════════════════════════════════════════════════════════════════
Airy, premium, editorial travel-brand feel. Warm dark-brown text on the pastel mint/cream
illustration, one coral-orange accent used only for the field icons and the Browse button.
Hero copy sits left-of-center in the upper portion of the viewport (the 16vh bottom padding
pushes it up so the illustration's foreground meadow stays visible); the white search card
floats to its right. Everything must load and animate correctly as a plain file:// page.
[/hidecontent]
← 返回首页