FAQ Chat — intrebari si raspunsuri ca intr-o conversatie
Produs Codegrid: Scroll-Powered FAQ Animation (pachetul codegrid-crency-animated-faq). Pagina live: /faq-chat/. Sursa: un build Vite cu un modul ES si o foaie de stil. Nicio imagine — tot efectul e cod.
Ce face
- Fiecare intrebare si fiecare raspuns e un balon de chat. Intrebarile stau in stanga, raspunsurile in dreapta.
- Balonul porneste ca un cerc de 64px cu trei puncte care „scriu” (animatie CSS pura,
typing-pulse) si e ascuns lascale: 0. - Cand urca la 85% din ecran, cercul apare. La 75%, punctele dispar, cercul se intinde la latimea reala, apoi la inaltimea reala (cele doua se suprapun 0.2s), iar randurile de text apar pe rand.
- La derulare inapoi, balonul se strange intai inapoi in cerc si abia apoi dispare. Ordinea e tinuta de un flag,
collapseWhenDone: daca balonul era deschis, cercul asteapta sfarsitul inchiderii (onReverseComplete) inainte sa se micsoreze. - Randul care tine balonul primeste de la inceput
min-heightegal cu inaltimea balonului deschis, asa ca nimic de dedesubt nu sare cand balonul se deschide.
Ce cere site-ul
- GSAP 3.13.0 + ScrollTrigger — deja globale pe site. Sursa cerea 3.15; nu foloseste nimic ce 3.13 nu are.
- Lenis 1.1.13 prin
import()dinamic, doar pe pagina asta, pe fereastra (ca pe celelalte pagini cu Lenis). Sursa cerea 1.3.26. Lenis e optional aici: daca nu se incarca, pagina merge cu scroll nativ — animatia nu depinde de el. - Fonturi: Barlow Condensed (titluri) si Host Grotesk (text), ambele noi pe site, doar aici.
- Conversie rem → px peste tot, si in CSS, si in cele trei valori din JS (
2remsi1.5rempentru padding,2rempentru colturi). Tema are baza rem de 10px.
Doua reparatii fata de sursa
1. Fonturile. Sursa masoara fiecare balon imediat ce ruleaza scriptul. Daca fontul web nu a venit inca, masoara textul in fontul de rezerva si balonul se deschide la o dimensiune gresita — prea lat sau taiat jos. Aici masuratoarea asteapta document.fonts.ready.
2. Redimensionarea. Sursa masoara o singura data. Dupa o schimbare de latime (fereastra trasa, telefon rotit) baloanele se deschideau la dimensiunea veche. Aici tot ce construieste scriptul sta intr-un gsap.context(). La o schimbare de latime (nu de inaltime — bara de adresa de pe telefon schimba doar inaltimea), contextul e anulat cu ctx.revert(): dispar stilurile inline si ScrollTrigger-ele. Apoi totul e construit din nou din masuratori proaspete. Baloanele deja trecute de prag se redeschid singure, pentru ca ScrollTrigger declanseaza onEnter la creare daca pozitia e deja depasita.
Verificat intr-un browser real: la 390px baloanele au 236px latime, dupa redimensionare la 1280px au 422px / 605px / 354px, fara text taiat.
Cum e construit in Bricks
O sectiune, un element Code. Markup 3,4 KB, CSS 4 KB, JS 6,9 KB.
- Radacina: sectiunea
.cfaq,_padding0,_width: 100%. Element Code cunoRoot,executeCode,language: html,signature => wp_hash($code). - Page settings:
bodyClasses: cfaq,headerDisabled,footerDisabled,disableLazyLoad. - Sursa stilizeaza global
*,h1,p,sectionsibody. Toate sunt scopate sub.cfaqsaubody.cfaq. Culorile (--base-100/200/300) stau pebody.cfaq, nu pe:root. Keyframe-ul are prefix:cfaq-typing-pulse. - Ascunderea barei de scroll din sursa (
::-webkit-scrollbarglobal) e legata de pagina prinhtml:has(body.cfaq). - Ca sa adaugi o intrebare, copiezi un bloc
.faq-item. Scriptul ia singur fiecare.faq-message, oricate ar fi. - Constantele de reglaj sunt sus in JS:
BUBBLE_SIZE,START_POP,START_EXPAND,POP_DURATION,EXPAND_DURATION,PAD_X,PAD_Y,RADIUS. Ultimele trei trebuie sa se potriveasca cu CSS-ul balonului.
Capcane
- Scroll greu, uitat la prima publicare. Tema are
html { scroll-behavior: smooth }. Lenis scrie pozitia de scroll la fiecare cadru, iar cu scroll-ul neted nativ activ fiecare scriere porneste o animatie a browserului — cele doua se bat si pagina se simte greoaie. Lenis are CSS-ul lui (html.lenis { scroll-behavior: auto !important }si restul), dar nu vine cu el cand e importat ca modul ES. Trebuie pus in CSS-ul paginii, ca la LeoParpeix si Studio Monet. Verificare:getComputedStyle(document.documentElement).scrollBehaviortrebuie sa deaauto. minHeightca numar nu merge.gsap.set(row, { minHeight: 77 })nu scrie nimic cand valoarea calculata de pornire eauto— fara eroare, pur si simplu nimic. Cu'77px'(sir cu unitate) merge. Sursa scria directstyle.minHeight, deci nu avea problema; a aparut cand am mutat-o ingsap.setca sa o prindactx.revert().letter-spacing: -1%peh1— procentele nu sunt valide acolo. Ignorat de browser si in sursa, si aici; pastrat cu comentariu.- Tabul ascuns ingheata totul. In tabul de automatizare pus in fundal,
requestAnimationFrameruleaza la 0 cadre, iar timerele sunt amanate pana la un minut. Baloanele raman cercuri si redimensionarea pare ca nu reconstruieste nimic. Verificarea s-a facut fortand progresul (onEnter()pe fiecare ScrollTrigger, apoiprogress(1)pe toate timeline-urile) si, pentru redimensionare, intr-un browser headless vizibil.
Pasi de reproducere
- Scopeaza CSS-ul sub
.cfaq; muta variabilele si fundalul de pe:root/bodypebody.cfaq. Converteste rem in px (×16), inclusiv valorile din JS. - Aplatizeaza
script.jsintr-un IIFE cu garda de DOM gata si garda de rulare dubla.gsapsiScrollTriggerdin global, Lenis prinimport()cucatchcare lasa scroll-ul nativ. - Leaga Lenis de
gsap.tickersi cheamagsap.ticker.wake()—ticker.addsingur nu trezeste un ticker adormit. - Pune construirea baloanelor intr-o functie
build()care ruleaza intr-ungsap.context(), dupadocument.fonts.ready. La schimbare de latime (debounce 200ms):ctx.revert(), apoibuild(). - Scrie arborele cu
wp_slash()sisignature => wp_hash($code), verifica md5 la citire, apoi regenereaza CSS-ul Bricks. - Verifica: 12 ScrollTrigger-e (doua pe balon), fiecare rand cu
min-heightin px, dupa deschidere niciun balon cu text taiat (scrollHeight≤clientHeight), la derulare inapoi toate lascale 0si 64px. Zero overflow orizontal la latime mare si la 390px.