Măsurare · front-end
Trei feluri în care browserul îți arată o pagină pe care vizitatorul n-o primește
Trei defecte de pe site-ul acesta au trecut de orice captură și au picat la orice măsurătoare: Chrome headless care refuză un layout de telefon, lazy loading care nu pornește într-o bandă care se derulează lateral și o animație condusă de scroll care a ascuns conținut definitiv. Un al patrulea, din CSS grid, a împins o coloană de subsol în afara ecranului la lățime de telefon. Toate patru au fost găsite prin măsurare, iar cifrele de mai jos sunt de pe acest site.
Publicat
Ce a arătat browserul și ce a primit vizitatorul
Am construit site-ul acesta și l-am verificat în modul obișnuit. Deschizi pagina, faci o captură la câteva lățimi, te uiți. Metoda a lăsat să treacă trei defecte de care s-ar fi lovit un vizitator și pe care măsurătoarea le-a prins imediat. Un al patrulea, în subsol, era ascuns de o regulă scrisă chiar de noi.
Cele trei au aceeași formă. Browserul redă ceva ce nu ajunge niciodată la un vizitator. În două cazuri captura e corectă în privința pixelilor pe care îi conține și mincinoasă în privința layoutului din spatele lor. În al treilea caz conținutul nu e deloc pe ecran, deci nu ai la ce să te uiți ca să-ți dai seama.
Mai jos e, pentru fiecare defect, ce este, cum a fost măsurat și ce număr a ieșit. Nimic din toate astea nu depinde de codul nostru. Aceleași verificări merg pe orice pagină.
Chrome headless nu redă un layout de lățime de telefon
Chrome în modul headless limitează viewportul de layout la circa 500 pixeli CSS. Ceri o fereastră de 390 de pixeli și primești o imagine de 390 de pixeli dintr-un layout de 500. E o decupare, nu o randare.
Am verificat cu o pagină-sondă care își scrie propriul window.innerWidth în document, ca valoarea să ajungă în captură, nu într-o consolă pe care poate n-o citim. Cu o fereastră de 390, pagina a scris 500.
De aici vin două lucruri. Conținutul tăiat de decupare arată exact ca un bug de depășire pe orizontală, așa că pornești în căutarea unei depășiri care nu există. Și nicio media query sub 500 de pixeli nu se execută vreodată. Acolo stau problemele reale de telefon, iar unealta nu ajunge acolo.
Soluția e emularea de dispozitiv prin protocolul de depanare, nu o dimensiune de fereastră. Emularea setează chiar viewportul de layout, așa că media query-urile de sub prag ajung în sfârșit să ruleze.
Lazy loading nu pornește într-o bandă care se derulează lateral
O bandă de tip marquee e o pistă mai lată decât containerul ei, mutată lateral cu un transform, într-un container cu overflow: hidden. Pentru ochi e mișcare. Pentru browser e un element foarte lat, cu cea mai mare parte din el în afara casetei.
O imagine împinsă lateral în afara containerului nu intră niciodată în viewport. Un browser care respectă loading="lazy" are deci dreptate să n-o încarce. Imaginile rămân goale și rămân goale la nesfârșit, fiindcă transformul care le mută nu înseamnă, pentru browser, că imaginea se apropie de viewport.
Măsurat pe site-ul acesta: 39 din 56 de imagini dintr-o bandă nu s-au încărcat niciodată. S-a reparat. Mai târziu aceeași greșeală a fost reintrodusă într-o a doua bandă și prinsă din nou la 8 din 28.
A doua cifră contează mai mult decât prima. Știam cauza, o scrisesem și am făcut-o din nou. Faptul că știi modul de eșec nu l-a împiedicat. Verificarea, da.
Aici am greșit: cauza era chiar regula de accesibilitate
O animație condusă de scroll, cu un fill mode, își păstrează starea inițială până începe intervalul. Așa e specificat și de obicei asta vrei. Devine defect când intervalul nu începe niciodată: o pagină prea scurtă ca să poată fi derulată, un viewport neobișnuit, orice situație în care poziția de scroll care ar porni animația nu poate fi atinsă. Elementul rămâne pentru totdeauna în starea inițială. Dacă starea aia e opacitate zero, conținutul pur și simplu nu există.
Aici e partea la care ne-am înșelat. Considerasem ramura de reduced motion varianta sigură prin definiție: mai puțină mișcare, aceeași pagină. Nu e așa. O regulă globală care reduce la zero durata oricărei animații sub reduced motion a anulat și animația care făcea poziționarea. O scenă care distribuia elementele pe un cerc le-a stivuit pe toate într-un singur punct.
Ramura de accesibilitate nu era o versiune degradată a paginii. Era altă pagină, și mai proastă. Am văzut-o doar pentru că am randat în ambele regimuri de mișcare, nu în unul singur. Dacă verificam doar regimul implicit, versiunea servită oamenilor care cer mai puțină mișcare ar fi plecat stricată.
Regula rezultată e îngustă și fără excepții. Un efect condus de scroll are voie să anime transform. Niciodată opacity. Poziția poate depinde de scroll. Existența, nu.
1fr nu înseamnă minim zero
În CSS grid, 1fr nu înseamnă „atât de mic cât e nevoie”. Înseamnă minmax(auto, 1fr), iar minimul auto e minimul conținutului. Un singur cuvânt care nu se poate rupe ridică lățimea minimă a coloanei, iar un grid care încape peste tot încetează să încapă.
O adresă de e-mail i-a făcut exact asta unei coloane întregi din subsol, la lățime de telefon. A împins coloana în afara ecranului. O regulă pe body care ascundea depășirea pe orizontală nu lăsa pagina să arate bară de derulare, așa că singurul simptom era conținut care nu era unde trebuia și la care nu aveai cum să ajungi.
Concluzia e mică. Tratează o regulă globală care ascunde depășirea drept ceva care suprimă dovezi, nu ceva care repară layouturi.
Cum faci aceleași verificări
Verifică viewportul înainte să ai încredere în captură. Încarcă o pagină-sondă care scrie window.innerWidth și valoarea clientWidth a elementului rădăcină ca text vizibil. Dacă numărul nu e cel cerut, captura e o decupare, iar orice concluzie trasă din ea e despre un layout pe care nu l-ai cerut.
Verifică imaginile după stare, nu cu ochiul. După load și după ce pagina s-a așezat, numără imaginile la care proprietatea complete e false. Rulează numărătoarea mai ales în interiorul containerelor cu derulare pe orizontală, fiindcă acolo iese diferită de zero în timp ce captura arată plină.
Compară lățime cu lățime. Pune lățimea de scroll a documentului față în față cu lățimea viewportului, la fiecare breakpoint, cu regula care ascunde depășirea dezactivată temporar. Ascunderea depășirii nu elimină depășirea. Elimină bara de derulare care ți-ar fi spus.
Randează în ambele regimuri de mișcare. O dată cu reduced motion activat și o dată fără, apoi compară pozițiile elementelor care se animă. Acolo unde un element e așezat într-un regim și nu în celălalt, ai găsit ori un defect, ori cele două pagini diferite pe care le livrezi.
Limite
Textul descrie comportamentul browserelor în august 2026. Limitarea din headless e, mai ales ea, un detaliu de implementare, nu un standard. Se poate schimba, iar reacția corectă e să rulezi din nou sonda, nu să te iei după numărul din articolul acesta.
Cifrele vin din markupul acestui site. 39 din 56 și 8 din 28 spun că modul de eșec există și se poate detecta. Nu spun nimic despre cât de răspândit e pe web și nimic despre câte imagini ar rata o altă bandă, în altă parte.
Verificările detectează absențe: o imagine care nu s-a încărcat, un element care nu s-a așezat, o pagină mai lată decât viewportul ei. Nu îți spun dacă layoutul e bun, dacă textul încape sau dacă un dispozitiv real, pe o rețea reală, se comportă la fel. Reduc ce mai are de verificat un om cu telefonul în mână. Nu îl înlocuiesc.
Și fiecare dintre defectele astea a fost găsit fiindcă cineva s-a gândit să măsoare exact acel lucru. Un defect la care nimeni nu s-a gândit e tot acolo, iar articolul acesta nu e dovadă că nu e.
Întrebări și răspunsuri
De ce arată greșit capturile făcute cu Chrome headless la lățime de telefon?
Capturile făcute cu Chrome headless la lățime de telefon arată greșit pentru că Chrome headless limitează viewportul de layout la circa 500 de pixeli CSS. O fereastră de 390 de pixeli dă o decupare de 390 de pixeli dintr-un layout de 500. Decuparea seamănă cu un bug de depășire care nu există, iar media query-urile sub 500 de pixeli nu rulează. Emularea de dispozitiv prin protocolul de depanare rezolvă problema.
De ce nu se încarcă imaginile lazy într-o bandă de tip marquee?
Imaginile lazy nu se încarcă într-o bandă de tip marquee pentru că pista e mutată lateral cu un transform, într-un container cu overflow: hidden, iar imaginile împinse în afara lui nu intră niciodată în viewport. Un browser care respectă loading="lazy" are dreptate să nu le încarce. Pe un site, 39 din 56 de imagini dintr-o bandă nu s-au încărcat niciodată. Numărarea imaginilor cu complete pe false prinde problema.
Poate o animație condusă de scroll să ascundă definitiv conținut?
O animație condusă de scroll poate ascunde definitiv conținut atunci când are un fill mode și intervalul ei nu începe niciodată. Animația își păstrează starea inițială până la începutul intervalului, așa că pe o pagină prea scurtă ca să se deruleze elementul rămâne pentru totdeauna în starea aceea. Dacă starea inițială e opacitate zero, conținutul dispare. Regula sigură: scroll-ul poate anima transform, niciodată opacity.
Varianta cu reduced motion a unei pagini e automat mai sigură?
Varianta cu reduced motion a unei pagini nu e automat mai sigură. O regulă globală care reduce la zero durata oricărei animații sub reduced motion poate anula și animația care poziționează elementele: într-un caz, o scenă care distribuia elementele pe un cerc le-a stivuit pe toate într-un singur punct. Diferența se vede doar dacă randezi pagina în ambele regimuri de mișcare și compari pozițiile elementelor.
De ce iese din ecran o coloană CSS grid cu 1fr pe telefon?
O coloană CSS grid cu 1fr poate ieși din ecran pe telefon pentru că 1fr înseamnă minmax(auto, 1fr), iar minimul auto e minimul conținutului. Un singur cuvânt care nu se poate rupe, cum ar fi o adresă de e-mail, ridică acest minim, iar un grid care încape în rest nu mai încape. O regulă pe body care ascunde depășirea elimină apoi bara de derulare, deci conținutul rămâne inaccesibil.
Cum verific o pagină web pentru defecte pe care capturile nu le arată?
O pagină web se verifică pentru defecte pe care capturile nu le arată prin măsurare, nu prin privire. Încarci o pagină-sondă care afișează window.innerWidth, numeri imaginile cu complete pe false, compari lățimea de scroll a documentului cu lățimea viewportului cu ascunderea depășirii dezactivată și randezi în ambele regimuri de mișcare. Verificările detectează absențe, dar nu înlocuiesc un om care testează pe un telefon real.
Cum se citează
Going Stellar (2026). Trei feluri în care browserul îți arată o pagină pe care vizitatorul n-o primește. GOING STELLAR S.R.L..
https://goingstellar.ro/ro/cercetare/browserul-arata-trei-pagini-pe-care-vizitatorul-nu-le-vede/