Utilizzare il flusso di lettura CSS per la navigazione sequenziale logica dello stato attivo

Data di pubblicazione: 1° maggio 2025

Le proprietà CSS reading-flow e reading-order sono disponibili a partire da Chrome 137. Questo post spiega i motivi alla base della progettazione di queste proprietà e fornisce alcuni brevi dettagli per iniziare a utilizzarle.

I metodi di layout come griglia e flex hanno trasformato lo sviluppo frontend, ma la loro flessibilità può causare problemi per alcuni utenti. È molto facile creare una situazione in cui l'ordine visivo non corrisponde all'ordine di origine nell'albero DOM. Poiché questo ordine delle origini è quello seguito dal browser se navighi nel sito utilizzando una tastiera, alcuni utenti possono riscontrare salti imprevisti mentre navigano in una pagina.

Le proprietà reading-flow e reading-order sono state progettate e aggiunte alla specifica CSS Display per cercare di risolvere questo problema di lunga data.

reading-flow

La proprietà CSS reading-flow controlla l'ordine in cui gli elementi in un layout flessibile, a griglia o a blocchi vengono esposti agli strumenti di accessibilità e come vengono selezionati utilizzando metodi di navigazione sequenziale lineare.

Accetta un valore della parola chiave, con un valore predefinito di normal, che mantiene il comportamento di ordinamento degli elementi nell'ordine DOM. Per utilizzarlo all'interno di un contenitore flessibile, imposta il valore su flex-visual o flex-flow. Per utilizzarlo all'interno di un contenitore a griglia, imposta il valore su grid-rows, grid-columns o grid-order.

reading-order

La proprietà CSS reading-order consente di eseguire manualmente l'override dell'ordine degli elementi all'interno di un contenitore del flusso di lettura. Per utilizzare questa proprietà all'interno di un container a griglia, flessibile o a blocchi, imposta il valore reading-flow del container su source-order e il valore reading-order del singolo elemento su un numero intero.

Esempio in flexbox

Ad esempio, potresti avere un contenitore di layout flessibile con tre elementi in ordine di riga inverso e voler utilizzare anche la proprietà order per riordinare l'ordine.

<div class="box">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
</div>
.box {
  display: flex;
  flex-direction: row-reverse;
}

.box :nth-child(1) {
  order: 2;
}

Puoi provare a navigare tra questi elementi utilizzando il tasto TAB per trovare l'elemento selezionabile successivo e i tasti TAB+MAIUSC per trovare l'elemento selezionabile precedente. Gli elementi sono elencati nell'ordine di origine: Uno, Due, Tre.

Dal punto di vista dell'utente finale, questa situazione non ha senso e può essere molto confusa. La stessa cosa accade se utilizziamo uno strumento di navigazione spaziale per l'accessibilità per navigare nella pagina.

Per risolvere il problema, imposta la proprietà reading-flow:

.box {
  reading-flow: flex-visual;
}

L'ordine di messa a fuoco ora è: 1, 3, 2. Questo è lo stesso ordine visivo che otterresti se leggessi in inglese da sinistra a destra.

Se invece preferisci mantenere l'ordine di messa a fuoco come era originariamente previsto, in ordine inverso, puoi impostare:

.box {
  reading-flow: flex-flow;
}

L'ordine di messa a fuoco è ora l'ordine flessibile inverso: Due, Tre, Uno. In entrambi i casi, viene presa in considerazione la proprietà CSS order.

Esempio con layout a griglia

Per vedere come funziona in una griglia, immagina di creare un layout con elementi di posizionamento automatico della griglia CSS con dodici aree selezionabili.

<div class="wrapper">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
 <a href="#">Four</a>
 <a href="#">Five</a>
 <a href="#">Six</a>
 <a href="#">Seven</a>
 <a href="#">Eight</a>
 <a href="#">Nine</a>
 <a href="#">Ten</a>
 <a href="#">Eleven</a>
 <a href="#">Twelve</a>
</div>

Vuoi che il quinto figlio occupi lo spazio più grande in alto, seguito dal secondo figlio verso il centro della griglia. Tutti gli altri elementi secondari possono essere posizionati automaticamente all'interno della griglia seguendo un modello di colonna.

.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
}
.wrapper a:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper a:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

Prova a navigare tra questi elementi utilizzando il tasto TAB per trovare l'elemento successivo su cui è possibile mettere il focus e i tasti TAB+MAIUSC per trovare l'elemento precedente su cui è possibile mettere il focus. Segue gli articoli nell'ordine di origine: da 1 a 12.

Per risolvere il problema, imposta la proprietà reading-flow:

.wrapper {
  reading-flow: grid-rows;
}

L'ordine di messa a fuoco è ora: cinque, uno, tre, due, quattro, sei, sette, otto, nove, dieci, undici, dodici. Segue l'ordine visivo, riga per riga.

Se vuoi che il flusso di lettura segua l'ordine delle colonne, puoi utilizzare il valore della parola chiave grid-columns. L'ordine di messa a fuoco diventa quindi Cinque, Sei, Nove, Sette, Dieci, Uno, Due, Undici, Tre, Quattro, Otto, Dodici.

.wrapper {
  reading-flow: grid-columns;
}

Puoi anche provare a utilizzare grid-order. L'ordine di messa a fuoco rimane da 1 a 12. Questo perché non è stato impostato alcun ordine CSS per nessun articolo.

Un contenitore di blocchi che utilizza reading-order

La proprietà reading-order consente di specificare in quale punto del flusso di lettura deve essere visitato un elemento, ignorando l'ordine impostato dalla proprietà reading-flow. Ha effetto solo su un contenitore di flusso di lettura valido, quando la proprietà reading-flow non è normal.

.wrapper {
  display: block;
  reading-flow: source-order;
}

.top {
  reading-order: -1;
  inset-inline-start: 50px;
  inset-block-start: 50px;
}

Il seguente contenitore di blocchi contiene cinque elementi. Non esistono regole di layout che riordinano gli elementi rispetto all'ordine di origine, ma esiste un elemento fuori flusso che deve essere visitato per primo.

<div class="wrapper">
  <a href="#">Item 1</a>
  <a href="#">Item 2</a>
  <a href="#">Item 3</a>
  <a href="#">Item 4</a>
  <a class="top" href="#">Item 5</a>
</div>

Se imposti reading-order di questo elemento su -1, l'ordine di messa a fuoco lo visita per primo prima di tornare all'ordine di origine per il resto degli elementi del flusso di lettura.

Puoi trovare altri esempi sul sito chrome.dev.

Interazione con tabindex

Storicamente, gli sviluppatori hanno utilizzato l'attributo globale HTML tabindex per rendere gli elementi HTML selezionabili e determinare l'ordine relativo per la navigazione sequenziale. Tuttavia, questo attributo presenta molti svantaggi e problemi di accessibilità. Il problema principale è che la navigazione con il tasto Tab creata utilizzando un valore positivo per tabindex non viene riconosciuta dalla struttura di accessibilità. Se utilizzato in modo errato, l'ordine di messa a fuoco potrebbe risultare instabile e non corrispondere all'esperienza con uno screen reader. Per risolvere il problema, monitora l'ordine utilizzando l'attributo HTML aria-owns.

Nell'esempio precedente di flex, per ottenere lo stesso risultato dell'utilizzo di reading-flow: flex-visual, puoi procedere nel seguente modo.

<div class="box" aria-owns="one three two">
  <a href="#" tabindex="1" id="one">One</a>
  <a href="#" tabindex="3" id="two">Two</a>
  <a href="#" tabindex="2" id="three">Three</a>
</div>

Ma cosa succede se anche un altro elemento al di fuori del contenitore ha tabindex=1? Quindi, tutti gli elementi con tabindex=1 verranno visitati insieme, prima di passare al valore di tabindex incrementale successivo. Questa navigazione sequenziale a scatti comporterà un'esperienza utente negativa. Pertanto, gli esperti di accessibilità consigliano di evitare tabindex positivi. Abbiamo cercato di risolvere il problema durante la progettazione di reading-flow.

Un container con la proprietà reading-flow impostata diventa proprietario dell'ambito di messa a fuoco. Ciò significa che la navigazione sequenziale dello stato attivo visita ogni elemento all'interno del contenitore prima di passare all'elemento attivabile successivo in un documento web. Inoltre, i relativi elementi secondari diretti vengono ordinati utilizzando la proprietà di flusso di lettura e tabindex positivo viene ignorato ai fini dell'ordinamento. È comunque possibile impostare un tabindex positivo sui discendenti di un elemento del flusso di lettura.

Tieni presente che un elemento con display: contents che eredita la proprietà reading-flow dal relativo contenitore di layout sarà anche un contenitore di flusso di lettura valido. Tienilo presente quando progetti il tuo sito. Scopri di più nella nostra richiesta di feedback su reading-flow e display: contents.

Contattaci

Prova gli esempi in questo post e negli esempi di reading-flow su chrome.dev e utilizza queste proprietà CSS sui tuoi siti. Se hai feedback, segnalalo come problema nel repository GitHub del gruppo di lavoro CSS. Se hai un feedback specifico sul comportamento di tabindex e ambito di messa a fuoco, segnalalo come problema nel repository GitHub di HTML WHATNOT. Ci farebbe piacere ricevere il tuo feedback su questa funzionalità.