Ierarhia titlurilor h1/h2/h3
Closes #17 (closed)
Patru probleme, toate invizibile pe ecran și toate în ce citește Google.
Ce s-a schimbat
Fișele de produs aveau două h1 identice. Cele două blocuri de titlu stau
în locuri structural diferite — deasupra galeriei pe telefon, în capul coloanei
de informații pe calculator — deci ambele sunt în DOM și CSS-ul ascunde unul.
Blocul de telefon păstrează elementul h1 (indexarea se face mobile-first, iar
acolo el e titlul vizibil), iar cel de calculator poartă nivelul doar în arborele
de accesibilitate. Fiecare e display: none la lățimea celuilalt, deci se expune
exact un titlu de nivel 1.
h1-ul primei pagini era sloganul bannerului, deci subiectul paginii se
schimba odată cu carusela, depindea de ce scria cineva în panou și era un spațiu
neîntrerupt cât timp cererea către /api/banners era în curs. Acum prima pagină
are un h1 fix și invizibil, cu exact textul folosit deja ca titlu de pagină și
ca h1 în varianta servită de server. Sloganul rămâne ce este: text de reclamă.
Paginile de colecție săreau de la nivel 1 la nivel 3. Banda de categorii și grila de produse primesc fiecare câte un titlu invizibil. Titlul grilei stă în afara ramurii condiționale, deci îl are și starea „niciun produs".
Subsolul era scris de două ori, o dată pentru telefon și o dată pentru
calculator, deci fiecare pagină din magazin conținea de două ori toate linkurile,
titlul de newsletter și sigla. Acum e un singur arbore: ordinea din DOM e cea
stivuită, pentru telefon și pentru un crawler mobile-first, iar aranjamentul de
calculator vine din poziționare explicită pe grilă. Coloanele sunt o singură
componentă, cu titlul h3 o singură dată.
Verificare
Măsurat în browser, build de producție și baza reală, versiunea veche față de cea nouă, la 390px și la 1440px:
| Înainte | După | |
|---|---|---|
h1 pe fișa de produs |
2 | 1 |
h1 pe prima pagină |
sloganul bannerului | titlu fix al magazinului |
Salt de nivel pe /collections/shop-all
|
1 → 3 | 1 → 2 → 3 |
| Titlu de newsletter în subsol | 2 | 1 |
| Linkuri în subsol | 36, din care 13 duplicate | 23, zero duplicate |
| Înălțimea subsolului | 714 / 997 px | 714 / 997 px |
Diferența de geometrie a subsolului: zero. Fiecare element și fiecare nod de text stă la aceleași coordonate, cu aceeași mărime, grosime și culoare de literă. Acordeonul de pe telefon se deschide la aceeași înălțime (1423px), iar pe calculator starea lui nu are niciun efect. Heroul primei pagini e identic la ambele lățimi, inclusiv poziția în pagină — titlul invizibil nu ocupă spațiu.
npx tsc --noEmit -p tsconfig.app.json curat; oxlint doar cu avertismentul
preexistent din src/App.tsx; npm run test 408 de teste în 32 de fișiere, toate
trecute (12 teste noi, unul pe fiecare defect); npm run build curat.
Două compromisuri, asumate
- Ordinea de tabulare pe calculator se schimbă. Aceleași 23 de linkuri, dar cele cinci sociale vin acum înaintea celor patru linkuri mari, pentru că ordinea din DOM e cea de telefon. Într-un arbore unic doar o lățime își poate păstra ordinea; nepotrivirea a fost pusă pe calculator, unde cele două zone stau una lângă alta, nu pe telefon, unde tabularea ar fi sărit în josul paginii și înapoi. La 390px ordinea e neschimbată.
- Trei opriri de tabulare în plus pe calculator. Titlurile de coloană sunt butoane la orice lățime, deci peste 1024px pot primi focus, deși nu fac nimic. Varianta cu detectarea pragului în JavaScript a fost scrisă și apoi scoasă: un ascultător de media query care ratează un eveniment lasă butoanele accesibile doar cu mouse-ul pe telefon, adică un defect mai grav decât cel pe care îl repară. Diferența rămâne în CSS, care nu poate rămâne în urmă.