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.
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.
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.
Qui scorre il diario: commit, commenti, file caricati, in ordine di tempo. Cambiare scheda non ricarica la pagina e non ti fa perdere il punto — torni alla panoramica e la ritrovi com’era. Il contesto cambia, l’orientamento resta.
Gli allegati del progetto, dal più recente. Una tab è onesta quando ogni pannello è davvero un contesto a sé: se due schede mostrano quasi la stessa cosa, non erano due schede — era una sola, divisa per finta.
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.
Le ultime 24 ore, ora per ora. Una vista stretta per chi vuole sapere "cosa sta succedendo adesso", senza il rumore della settimana intera.
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.
Trenta giorni, raggruppati per settimana. Cambiare periodo non ricalcola tutto da capo agli occhi: la pillola scivola e il pannello cambia, ma resti nello stesso posto della pagina.
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.
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.
Otto messaggi spediti di recente. Il conteggio qui è meno urgente — è memoria, non richiamo — ma resta utile per orientarsi senza contare a mano.
Tre bozze in sospeso. Allineando le cifre con tabular-nums, il 3 e il 24 occupano lo stesso passo: la riga non si sposta quando un conteggio cambia.
Niente di archiviato per ora. Una tab a zero non finge un badge: il conteggio è spento, perché lo zero è una verità tranquilla, non un allarme.
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.
Il catalogo intero, senza filtri. È il punto di partenza: da qui si stringe verso un reparto, non il contrario.
Gli arrivi più recenti. Un reparto che cambia spesso, ed è il motivo per cui sta vicino all’inizio: ciò che si guarda di più, vicino al pollice.
Pentole, utensili, piccoli elettrodomestici. Molte tab significano molti contesti: lo scroll orizzontale li tiene tutti raggiungibili senza affollare la riga.
Tessili, illuminazione, complementi. Le sfumature ai lati dicono che a destra continua: senza, metà di questi reparti non verrebbe mai trovata.
Piante, vasi, attrezzi da esterno. Lo scroll-snap fa incastrare ogni tab al bordo, così non resti mai con un’etichetta tagliata a metà.
Attrezzatura e abbigliamento tecnico. Navigando con le frecce, la tab attiva viene riportata in vista da sola: non scompare mai fuori campo.
Narrativa, saggi, illustrati. Un reparto in coda non è meno importante — è solo meno frequente, e lo scroll lo tiene a portata senza rubargli spazio agli altri.
Sconti del momento, a tempo. Sta in fondo apposta: è una scorciatoia, non la porta principale, e la sfumatura a destra invita a scoprirla.
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.
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?