Opens in a new tab

ForgeAutomotive Menu — meniul care inghite pagina

Produs Codegrid: ForgeAutomotive Menu. Pagina live: /forgeautomotive-menu/. Sursa: un build Vite cu un modul ES, o foaie de stil, doua fotografii si doua logo-uri SVG.

Ce face

  • La apasarea butonului Menu, pagina nu aluneca si nu se estompeaza: se stringe spre centru si dispare intr-un punct. Doua proprietati fac asta simultan — clip-path trece de la dreptunghiul intreg la polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%), adica un patrulater cu toate colturile in acelasi loc, iar scale scade la 0.5.
  • In spatele ei, meniul asteapta la 350px in adancime (translateZ(350px) intr-un parinte cu perspective: 1000px), neclar si invizibil. Cand pagina se inchide, el vine spre tine: z la 0, blur de la 10px la 0, opacitate de la 0 la 1.
  • Cele doua miscari se suprapun 0.8 secunde din 1 — meniul porneste inainte ca pagina sa termine de plecat. Fara suprapunere ar fi doua gesturi in sir, nu unul singur.
  • Linkurile au rostogolire pe litera: fiecare link e duplicat in doua span-uri suprapuse, clona sta un rand mai jos (yPercent: 100), iar la hover perechile de litere urca impreuna. Array-ul e intretesut (original[0], clona[0], original[1], clona[1]…), asa ca decalajul parcurge cuvantul de la stanga la dreapta peste ambele copii deodata.
  • La iesirea cursorului aceeasi animatie merge inapoi, dar cu from: 'end' — decalajul porneste din coada cuvantului. Detaliul asta e ce face revenirea sa nu para o simpla derulare inversa.

Ce cere site-ul

  • GSAP 3.13.0 + SplitText — amandoua deja globale pe site.
  • Lenis 1.1.13 prin import() dinamic, doar pe pagina asta. Sursa cerea 1.3.26; am folosit versiunea pe care o au deja celelalte pagini cu Lenis, ca site-ul sa ramana cu o singura versiune.
  • Fonturi: DM Sans (il aveam) si Instrument Serif (nou pe site, doar aici).
  • Conversie rem → px peste tot. Tema are baza rem de 10px, deci clamp(2rem, 8vw, 14rem) de la linkurile mari ar fi iesit cu maximul la 140px in loc de 224px.

Lenis pe container, nu pe fereastra

Asta e partea care nu seamana cu nimic altceva de pe site. Celelalte patru pagini cu Lenis il lasa pe fereastra. Aici:

new Lenis({
  wrapper: .page-container,
  content: .page-content
})

Documentul nu deruleaza deloc. Deruleaza un div fix, cu overflow-y: auto, care ocupa tot ecranul. Motivul e chiar efectul: ca sa poti micsora si decupa pagina ca pe un obiect, pagina trebuie sa fie un obiect — un element cu marginile lui, nu corpul documentului.

Doua consecinte practice: body primeste overflow: hidden, si orice cod care presupune window.scrollY sau ScrollTrigger pe fereastra nu va vedea nimic pe pagina asta. Daca muti efectul pe un site de client, asta e prima intrebare de pus: ce altceva de pe pagina depinde de scroll-ul ferestrei?

Cum e construit in Bricks

O sectiune, un element Code. Markup 3 KB, CSS 5,8 KB, JS 5,3 KB.

  • Radacina: sectiunea .forge, _padding 0, _width: 100%. Element Code cu noRoot, executeCode, language: html, signature => wp_hash($code).
  • Page settings: bodyClasses: forge, headerDisabled, footerDisabled, disableLazyLoad.
  • Sursa stilizeaza global *, h1, p, a, img si nav. nav e cel periculos — ar fi prins header-ul site-ului. Toate sunt scopate sub .forge.
  • Butonul care deschide meniul era un <div> in sursa. L-am facut <button> cu aria-expanded: era singurul control al paginii si nu se putea ajunge la el cu tastatura. E singura abatere functionala de la sursa.

Capcane

  • Regula .char din CSS nu se aplica — reparat. SplitText din GSAP 3.13 nu mai adauga clasa char implicit, asa ca will-change: transform scris pentru litere nu ajungea la ele. Animatia mergea oricum (JS-ul animeaza array-ul .chars direct, nu prin selector). Acum ambele apeluri au charsClass: 'char'; verificat pe pagina: 76 de litere cu clasa, will-change: transform aplicat.
  • will-change: tranform — scris gresit in sursa, de doua ori (.menu-content si .page-container). Nu produce eroare, pur si simplu nu face nimic. Pastrat, cu /* sic */ alaturi, ca sa nu para greseala portarii.
  • letter-spacing: -2% pe h1 — procentele nu sunt valide acolo. Ignorat de browser si in sursa, si aici.
  • Capcana de verificare, si cea mai costisitoare: in tabul de automatizare pus in fundal, document.hidden devine true si requestAnimationFrame se opreste complet — masurat: 0 cadre pe secunda. Toate animatiile GSAP ingheata. Arata identic cu o pagina stricata: clic pe buton, aria-expanded se schimba, dar nimic nu se misca. Am tras exact concluzia gresita prima data. Verifica intai document.hidden si numara cadrele rAF, apoi forteaza progresul manual: tl.progress(1) pentru timeline, gsap.getTweensOf(el).forEach(t => t.progress(1)) pentru tween-urile de hover. Asa se vede adevarul fara sa depinzi de cadre.
  • Imaginile din sursa sunt 4000×3000, 3,7 MB impreuna — afisate oricum taiate la aspect-ratio: 16/9. Reduse la 1600px si JPEG q82: 590 KB.
  • Logo-urile sunt ale unui brand inventat („ForgeAutomotive”, plus un „Logoipsum” in footer). Bune pentru demo; daca piesa ajunge intr-o oferta, se schimba.

Pasi de reproducere

  1. Redimensioneaza cele doua fotografii la 1600px, JPEG q82 progresiv. Copiaza cele doua SVG-uri ca atare. Urca-le prin create-upload-link + base64 si verifica md5 la destinatie.
  2. Scopeaza CSS-ul sub .forge; muta regulile de body pe body.forge (aici doar overflow: hidden si fundalul). Converteste toti rem in px (×16), inclusiv style="width: 6rem" din markup.
  3. Aplatizeaza script.js intr-un IIFE cu garda de DOM gata si garda de rulare dubla. gsap si SplitText din global, Lenis prin import(). Toate cautarile prin root.
  4. Pastreaza bucla proprie requestAnimationFrame a sursei pentru Lenis — pagina nu foloseste ScrollTrigger, deci nu e nevoie de sincronizare cu gsap.ticker.
  5. Scrie arborele cu wp_slash() si signature => wp_hash($code), verifica md5 la citire, apoi regenereaza CSS-ul Bricks.
  6. Verifica fortand progresul, nu privind: timeline la progress(1) trebuie sa dea scale 0.5, clip-path strans in punct, opacitate 1 si blur 0 pe meniu; la progress(0) inapoi la scale 1, opacitate 0, blur 10px. Hover: literele de la 0 la -106px si inapoi la 0.
  7. Zero overflow orizontal la latime mare si in iframe de 390px — verifica si scrollWidth al lui .page-container, nu doar al documentului.