Capitolo 12

Anatomia di una tab

Una tab non sceglie un valore: cambia il contesto sotto i piedi. Il problema vero non è dove mettere l'indicatore, ma come spostare l'utente in un altro pannello senza fargli perdere il filo di dov'era.

11 min di lettura

Il capitolo sul toggle finiva con una distinzione netta: lo switch sceglie fra due posizioni, il controllo segmentato fra poche alternative pari-grado. Sembrava di aver chiuso il discorso, e invece la tab — che a uno sguardo distratto somiglia tantissimo a un segmented control — apre un capitolo diverso. La differenza non è grafica, è di funzione. Un segmented control sceglie un valore e quel valore resta lì, sotto lo stesso contenuto: la densità di una lista, l’unità di misura di un grafico. Una tab cambia il contesto: sotto ognuna c’è un pannello di contenuto diverso, e premerla significa «portami altrove».

È questa la domanda di tutto il capitolo: come si cambia contesto senza disorientare? Perché spostare qualcuno in un altro pannello è facilissimo — basta nasconderne uno e mostrarne un altro. La parte difficile è farlo in modo che l’utente sappia, in ogni istante, dov’è, dove può andare e dov’era prima. Una tab fatta male non è brutta: è spaesante. Mostra il pannello giusto ma cancella il senso di posizione, e l’utente si ritrova altrove senza ricordare come c’è arrivato.

La continuità si costruisce su due binari. Il primo è la semantica: non un radio group travestito, ma il pattern ARIA tabs vero — role="tablist", role="tab", role="tabpanel", aria-selected, le frecce ←/→ con Home/End, il roving tabindex che tiene una sola tab nel Tab order. Il secondo è il movimento: un indicatore che scivola fra le posizioni invece di lampeggiare, così l’occhio segue una cosa sola che si sposta e non perde il punto. Cinque dimostrazioni, cinque modi di tenere insieme questi due binari — dalla barra che fluisce al pannello che si dissolve con la View Transitions API.

L’indicatore che fluisce

La prima tab è anche la più comune: etichette in fila, una barra underline sotto quella attiva. Il punto non è la barra in sé, ma come si sposta quando cambi tab.

12.a
Progetto

La panoramica raccoglie lo stato del progetto in un colpo d’occhio: scadenze vicine, chi sta facendo cosa, cosa è in attesa di una tua risposta. È la prima scheda perché è la più richiesta — apri, capisci, decidi se serve andare oltre.

Underline che fluisce · ARIA tabs completo

Clicca una tab, o dai il focus e usa /, Home, Fine: l’underline non appare sotto la nuova etichetta, ci scorre. Sotto c’è una tecnica in stile FLIP — misuriamo posizione e larghezza della tab attiva e le scriviamo in due custom property (—ind-x, —ind-w), poi una transizione CSS di transform e inline-size fa il resto. Una barra sola che si sposta, non quattro che lampeggiano: è un indicatore di posizione, e gli indicatori scivolano. Questo è ciò che distingue una tab da un segmented control: qui sotto ogni etichetta c’è un tabpanel diverso, non un valore — per questo la semantica è il pattern ARIA tabs, con aria-controls dalla tab al suo pannello.

La continuità è tutta in quel movimento: l’occhio segue l’underline che viaggia e capisce da dove a dove si è spostato, senza riorientarsi da capo. Ma il pannello stesso non si ri-anima: il contenuto già visto si scambia di colpo, perché ri-animare ciò che hai già letto è nervosismo, non eleganza. La regola del playground — animare una volta, mai ri-animare — vale anche qui: l’underline porta la transizione, il testo resta fermo. E con prefers-reduced-motion l’underline non viaggia: si trova già sotto la tab scelta. Stesso stato finale, nessun viaggio.

La pillola, riusata per cambiare contesto

La seconda tab prende in prestito una meccanica già vista — la pillola che scivola del controllo segmentato — e la mette al servizio di un compito diverso. È un esercizio utile proprio perché la forma è quasi identica e il significato no.

12.b
Periodo

Sette giorni aggregati. È il periodo di default perché è quello in cui un andamento comincia a leggersi: abbastanza ampio da mostrare un trend, abbastanza stretto da restare leggibile.

Pill tabs · la lezione del segmented, contratto diverso

La pillola scivola dietro la tab attiva, esattamente come nel segmented control del capitolo 09: stesso trucco, una custom property —idx che trasla un elemento di sfondo a larghezza fissa (100%/N), nessuna misura in JS. Ma il contratto è cambiato sotto la pelle. Lì erano <input type=“radio”> che sceglievano un valore; qui sono role=“tab” che aprono pannelli. Confondere i due è l’errore che disorienta: una pillola che sembra scegliere «giorno / settimana / mese» come fosse un filtro, mentre in realtà ricarica un intero contesto — o viceversa. La forma densa e compatta sta dove la barra underline sarebbe troppo ariosa, ma la promessa dev’essere onesta su cosa succede quando la premi.

La tastiera è la stessa di ogni tab di questo capitolo: / ciclano la selezione, Home e Fine saltano agli estremi, e il roving tabindex tiene una sola tab raggiungibile con Tab — le altre escono dall’ordine e si raggiungono con le frecce, come vuole il pattern ARIA tabs. Cambiando periodo, il pannello non si ri-anima: la pillola porta la continuità, il contenuto si scambia netto. E con prefers-reduced-motion la pillola non scivola, è già dietro la tab scelta: lo stato finale è identico, sparisce solo il viaggio.

Il numero che non balla

La terza tab aggiunge un’informazione di servizio: un conteggio accanto all’etichetta, tipo «Posta in arrivo 24». Dice quanto c’è dietro la tab prima ancora di aprirla — ma un numero che cambia mette alla prova un dettaglio tipografico.

12.c
Casella

Ventiquattro messaggi non letti. Il numero è il vero richiamo della tab: dice "qui c’è qualcosa che ti aspetta" senza che tu debba aprire per scoprirlo.

Count tabs · tabular-nums perché il numero non balli

Il conteggio è il vero richiamo della tab: dice «qui c’è qualcosa che ti aspetta» senza che tu debba aprire per scoprirlo. Ma se le cifre non sono a passo fisso, una riga che passa da 9 a 10 — o due tab con 3 e 24 — si sposta di un soffio, e quel sobbalzo è rumore. Da qui la regola del capitolo 06: tabular-nums ovunque un numero cambi o vada confrontato in colonna, «così quando passa da 9 a 10 non sussulta». La cifra varia, la larghezza no. Il numero è anche dentro l’aria-label, così lo screen reader annuncia «Posta in arrivo, 24 elementi», non l’etichetta e il numero appiccicati.

L’onestà è nello zero. La tab «Archivio» è a 0, e non finge un badge rosso su niente: il conteggio è spento, scritto in grigio sottile, perché lo zero è una verità tranquilla, non un allarme. E il colore non è mai l’unico canale — resta la cifra 0 a dirlo, leggibile anche per chi non distingue il grigio dall’accento. Qui non c’è movimento da disabilitare: nessuna animazione, quindi prefers-reduced-motion non ha nulla da togliere. Va bene così — non tutto deve muoversi, e una tab che si limita a informare con precisione è già rispetto.

Quando le tab sono troppe

La quarta tab affronta il caso scomodo: le etichette sono più di quante ne stiano in una riga. Il riflesso sbagliato è rimpicciolire il testo o mandarle a capo; la risposta onesta è lasciarle scorrere — ma dichiarando che c’è altro.

12.d
Reparto

Il catalogo intero, senza filtri. È il punto di partenza: da qui si stringe verso un reparto, non il contrario.

Scroll-snap tabs · indicatori di overflow ai bordi

Trascina la fila orizzontalmente, o naviga con /: le tab scorrono e ognuna si «incastra» gentilmente al bordo (scroll-snap-type: x proximity), così non resti mai con un’etichetta tagliata a metà. Il bug di usabilità più comune di una barra scrollabile è il silenzio: niente dice che a destra continua, e metà delle tab non viene mai trovata. Qui una sfumatura su ciascun lato si accende solo quando da quel lato c’è davvero altro da scorrere — è un segnale di affordance guidato dallo scroll reale (scrollLeft vs scrollWidth), non una decorazione fissa.

Navigando con le frecce, la tab attiva viene riportata in vista da sola con scrollIntoView: non scompare mai fuori campo, anche se è l’ultima della fila. Ed è qui che prefers-reduced-motion incontra lo scroll: lo scorrimento verso la tab usa behavior: ‘smooth’ solo quando il movimento è gradito; con reduced motion diventa un salto secco (‘auto’), stessa destinazione senza il viaggio fluido. Le sfumature restano — non sono motion, sono informazione: dicono «c’è dell’altro», e quell’informazione serve a tutti, fermi o in movimento.

Il pannello che si dissolve

L’ultima tab sposta il movimento dall’indicatore al pannello. Finora la barra o la pillola portavano la continuità mentre i contenuti si scambiavano di colpo; qui è il pannello stesso a uscire ed entrare, con la View Transitions API a orchestrare il passaggio.

12.e
Profilo

Chi sei in poche righe, come ti presenti al primo sguardo. È il pannello che apre il profilo: il contesto più ampio, prima dei dettagli.

View Transition tabs · document.startViewTransition + fallback

Cambia tab: il vecchio pannello sfuma via mentre il nuovo entra, e il cross-fade non l’abbiamo scritto noi. document.startViewTransition cattura il «prima» e il «dopo» del pannello e interpola da sola — niente keyframe a mano per coordinare l’uscita di uno con l’entrata dell’altro. Restiamo fedeli alla legge del tempo del playground: le cose se ne vanno più in fretta di quanto entrino, e infatti ::view-transition-old dura meno di ::view-transition-new. Il pannello porta il movimento, ma l’indicatore underline resta a dire dove sei: le due cose non si pestano i piedi.

Il punto delicato è che una View Transition è un miglioramento progressivo, mai un requisito. Lo scambio di stato — hidden, aria-selected, roving tabindex — vive in una funzione a parte; la transizione è solo la confezione attorno. Dove l’API non esiste, si chiama quella funzione e basta: stesso pannello, stesso stato finale, solo senza la dissolvenza. E con prefers-reduced-motion le @keyframes della transizione sono disattivate esplicitamente — perché collassare le durate a 1ms non sempre basta per le animazioni con nome, vanno spente a mano. Lo scambio avviene comunque, istantaneo: il movimento è confezione, mai sostanza.


Cinque tab, una sola domanda: come si cambia contesto senza disorientare? La risposta non è mai stata «con l’animazione giusta». È stata, ogni volta, tenere fermo ciò che orienta mentre cambia ciò che informa. L’underline che fluisce dice da dove a dove ti sei spostato; la pillola riusa una meccanica nota senza barare sul contratto; il conteggio informa con cifre che non ballano; lo scroll-snap dichiara che c’è altro invece di nasconderlo; la View Transition confeziona il passaggio senza renderlo un requisito. E sotto tutto, immutabile, il pattern ARIA tabs: la tastiera che funziona, la posizione che si annuncia, il pannello che il browser sa collegare alla sua tab. La grafica della tab è l’ultima cosa; la prima è la promessa di non farti mai perdere dov’eri.

Il prossimo capitolo resta tra i contenitori ma cambia oggetto: dalla fila di pannelli al singolo riquadro che li raccoglie. Anatomia di una scheda — la card è solo un rettangolo con un bordo, o c’è una grammatica di gerarchia, affordance e zone cliccabili che decide se inviti a entrare o respingi?