Używanie CSS do tworzenia logicznej nawigacji sekwencyjnej z fokusem

Data publikacji: 1 maja 2025 r.

Właściwości CSS reading-flowreading-order są dostępne w Chrome 137. Z tego posta dowiesz się, dlaczego te właściwości zostały zaprojektowane w taki sposób, oraz poznasz kilka szczegółów, które pomogą Ci zacząć z nich korzystać.

Metody układu, takie jak siatka i flexbox, zmieniły sposób tworzenia interfejsu, ale ich elastyczność może być problematyczna dla niektórych użytkowników. Bardzo łatwo jest stworzyć sytuację, w której kolejność wizualna nie odpowiada kolejności źródłowej w drzewie DOM. Ponieważ przeglądarka kieruje się tą kolejnością źródeł podczas poruszania się po witrynie za pomocą klawiatury, niektórzy użytkownicy mogą napotkać nieoczekiwane przeskakiwanie podczas poruszania się po stronie.

Właściwości reading-flow i reading-order zostały zaprojektowane i dodane do specyfikacji CSS Display, aby rozwiązać ten długotrwały problem.

reading-flow

Właściwość CSS reading-flow określa kolejność, w jakiej elementy w układzie elastycznym, siatkowym lub blokowym są udostępniane narzędziom ułatwień dostępu i jak są zaznaczane za pomocą liniowych metod nawigacji sekwencyjnej.

Przyjmuje jedną wartość słowa kluczowego, domyślnie normal, która zachowuje kolejność elementów w modelu DOM. Aby użyć go w kontenerze elastycznym, ustaw jego wartość na flex-visual lub flex-flow. Aby użyć go w kontenerze siatki, ustaw jego wartość na grid-rows, grid-columns lub grid-order.

reading-order

Właściwość reading-order CSS umożliwia ręczne zastąpienie kolejności elementów w kontenerze przepływu odczytu. Aby użyć tej właściwości w kontenerze siatki, flex lub bloku, ustaw wartość reading-flow w kontenerze na source-order i ustaw wartość reading-order poszczególnych elementów na liczbę całkowitą.

Przykład w układzie flexbox

Możesz na przykład mieć kontener układu flex z 3 elementami w odwrotnej kolejności wierszy, a także używać właściwości order, aby zmienić tę kolejność.

<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;
}

Możesz spróbować poruszać się po tych elementach za pomocą klawisza TAB, aby znaleźć następny element, na którym można ustawić fokus, oraz klawiszy TAB+SHIFT, aby znaleźć poprzedni element, na którym można ustawić fokus. Kolejność elementów jest zgodna z kolejnością w źródle: One, Two, Three.

Z perspektywy użytkownika nie ma to sensu i może być bardzo mylące. To samo dzieje się, gdy do poruszania się po stronie używamy narzędzia do przestrzennej nawigacji ułatwień dostępu.

Aby rozwiązać ten problem, ustaw właściwość reading-flow:

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

Kolejność zaznaczania to teraz: 1, 3, 2. Jest to ten sam porządek wizualny, jaki uzyskałbyś, czytając tekst w języku angielskim od lewej do prawej.

Jeśli wolisz zachować pierwotną kolejność fokusu w odwrotnej kolejności, możesz ustawić:

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

Kolejność fokusu jest teraz odwrotna do kolejności elastycznej: 2, 3, 1. W obu przypadkach uwzględniana jest właściwość order usługi porównywania cen.

Przykład z układem siatki

Aby zobaczyć, jak to działa w siatce, wyobraź sobie, że tworzysz układ z elementami umieszczonymi automatycznie w siatce CSS, który ma 12 obszarów, na których można ustawić fokus.

<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>

Chcesz, aby piąty element podrzędny zajmował największą przestrzeń na samej górze, a drugi element podrzędny znajdował się w środkowej części siatki. Wszystkie pozostałe elementy podrzędne można automatycznie umieścić w siatce zgodnie z szablonem kolumny.

.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;
}

Spróbuj poruszać się po tych elementach za pomocą klawisza TAB, aby znaleźć następny element, na którym można ustawić fokus, oraz klawiszy TAB+SHIFT, aby znaleźć poprzedni element, na którym można ustawić fokus. Kolejność jest taka sama jak w przypadku elementów w zamówieniu źródłowym: od 1 do 12.

Aby rozwiązać ten problem, ustaw właściwość reading-flow:

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

Kolejność fokusu to teraz: 5, 1, 3, 2, 4, 6, 7, 8, 9, 10, 11, 12. Jest on zgodny z kolejnością wizualną, wiersz po wierszu.

Jeśli chcesz, aby kolejność odczytywania była zgodna z kolejnością kolumn, możesz użyć wartości słowa kluczowego grid-columns. Kolejność zaznaczania będzie wtedy następująca: Five, Six, Nine, Seven, Ten, One, Two, Eleven, Three, Four, Eight, Twelve.

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

Możesz też spróbować użyć grid-order. Kolejność skupienia pozostaje taka sama: od 1 do 12. Wynika to z tego, że w przypadku żadnego produktu nie ustawiono zamówienia w usłudze porównywania cen.

Kontener blokowy z użyciem reading-order

Właściwość reading-order pozwala określić, kiedy w toku odczytywania element powinien zostać odwiedzony, zastępując kolejność określoną przez właściwość reading-flow. Działa tylko w przypadku prawidłowego kontenera przepływu odczytu, gdy właściwość reading-flow nie ma wartości normal.

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

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

Poniższy kontener blokowy zawiera 5 elementów. Nie ma reguł układu, które zmieniają kolejność elementów w stosunku do kolejności źródłowej, ale jest jeden element poza przepływem, który powinien być odwiedzany jako pierwszy.

<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>

Jeśli ustawisz wartość reading-order tego elementu na -1, kolejność fokusu najpierw przejdzie do tego elementu, a potem wróci do kolejności źródłowej w przypadku pozostałych elementów przepływu odczytu.

Więcej przykładów znajdziesz na stronie chrome.dev.

Interakcja z atrybutem tabindex

W przeszłości programiści używali globalnego atrybutu HTML tabindex, aby umożliwić skupianie się na elementach HTML i określać względną kolejność nawigacji za pomocą sekwencyjnego skupiania. Ten atrybut ma jednak wiele wad i wątpliwości związanych z ułatwieniami dostępu. Głównym problemem jest to, że nawigacja za pomocą fokusu uporządkowanego przez atrybut tabindex utworzona przy użyciu dodatniej wartości tabindex nie jest rozpoznawana przez drzewo dostępności. Nieprawidłowe użycie może spowodować skakanie kolejności fokusu, która nie będzie pasować do działania czytnika ekranu. Aby to naprawić, śledź kolejność za pomocą atrybutu HTML aria-owns.

W poprzednim przykładzie z elastycznym układem, aby uzyskać taki sam wynik jak w przypadku użycia reading-flow: flex-visual, możesz wykonać te czynności:

<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>

Co jednak się stanie, jeśli inny element poza kontenerem również ma tabindex=1? Następnie wszystkie elementy z atrybutem tabindex=1 zostaną odwiedzone razem, zanim przejdziemy do następnej przyrostowej wartości atrybutu tabindex. Takie skokowe przechodzenie do kolejnych stron może negatywnie wpłynąć na wrażenia użytkowników. Dlatego eksperci ds. ułatwień dostępu zalecają unikanie dodatnich wartości atrybutu tabindex. Podczas projektowania reading-flow staraliśmy się rozwiązać ten problem.

Kontener, w którym ustawiono właściwość reading-flow, staje się właścicielem zakresu fokusu. Oznacza to, że sekwencyjna nawigacja za pomocą fokusu obejmuje wszystkie elementy w kontenerze, zanim przejdzie do następnego elementu, który można zaznaczyć w dokumencie internetowym. Ponadto jego bezpośrednie elementy podrzędne są uporządkowane za pomocą właściwości reading-flow, a dodatnie wartości tabindex są ignorowane na potrzeby porządkowania. Nadal można ustawić dodatni indeks tabulacji na elementach podrzędnych elementu przepływu odczytu.

Pamiętaj, że element z atrybutem display: contents, który dziedziczy właściwość reading-flow z elementu nadrzędnego układu, również będzie prawidłowym kontenerem przepływu odczytu. Pamiętaj o tym podczas projektowania witryny. Więcej informacji na ten temat znajdziesz w prośbie o opinię na temat reading-flowdisplay: contents.

Daj nam znać

Wypróbuj przykłady z tego posta i z reading-flowprzykładów na chrome.dev oraz używaj tych właściwości CSS w swoich witrynach. Jeśli masz jakieś uwagi, zgłoś je jako problem w repozytorium GitHub grupy roboczej CSS. Jeśli masz uwagi dotyczące konkretnie indeksu tabindex i zakresu fokusu, zgłoś je jako problem w repozytorium GitHub HTML WHATNOT. Chętnie poznamy Twoją opinię na temat tej funkcji.