Используйте поток чтения CSS для логической последовательной навигации по фокусу. Используйте поток чтения CSS для логической последовательной навигации по фокусу. Используйте поток чтения CSS для логической последовательной навигации по фокусу. Используйте поток чтения CSS для логической последовательной навигации по фокусу.

Опубликовано: 1 мая 2025 г.

Свойства CSS reading-flow и reading-order доступны начиная с Chrome версии 137. В этой статье объясняются причины создания этих свойств и приводятся краткие сведения, которые помогут вам начать с ними работать.

Методы компоновки, такие как grid и flex, преобразили разработку фронтенда, однако их гибкость может создавать проблемы для некоторых пользователей. Очень легко создать ситуацию, когда визуальный порядок не соответствует порядку элементов в DOM-дереве. Поскольку именно этот порядок элементов используется браузером при навигации по сайту с помощью клавиатуры, некоторые пользователи могут столкнуться с неожиданными скачками при перемещении по странице.

Свойства reading-flow и reading-order были разработаны и добавлены в спецификацию CSS Display , чтобы попытаться решить эту давнюю проблему.

reading-flow

Свойство CSS reading-flow управляет порядком отображения элементов в гибкой, сеточной или блочной компоновке для инструментов доступности, а также тем, как они получают фокус при использовании методов линейной последовательной навигации.

Он принимает одно ключевое значение, по умолчанию равное normal , которое сохраняет поведение упорядочивания элементов в порядке DOM. Чтобы использовать его внутри flex-контейнера, установите его значение либо на flex-visual , либо на flex-flow . Чтобы использовать его внутри grid-контейнера, установите его значение либо на grid-rows , grid-columns , либо grid-order .

reading-order

Свойство CSS ` reading-order позволяет вручную переопределять порядок элементов внутри контейнера, определяющего порядок чтения. Чтобы использовать это свойство внутри контейнера типа `grid`, `flex` или `block`, установите значение reading-flow для контейнера равным source-order , а для каждого отдельного элемента задайте ` reading-order в виде целочисленного значения.

Пример в flexbox

Например, у вас может быть контейнер с гибкой компоновкой, содержащий три элемента, расположенных в обратном порядке, и вы также хотите использовать свойство order для изменения порядка этих элементов.

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

Вы можете попробовать перемещаться по этим элементам, используя клавишу TAB для поиска следующего элемента, находящегося в фокусе, и клавиши TAB+SHIFT для поиска предыдущего элемента, находящегося в фокусе. Это соответствует порядку элементов в исходном коде: Один, Два, Три.

С точки зрения конечного пользователя, это не имеет смысла и может вызывать сильную путаницу. То же самое происходит, если мы используем инструмент пространственной навигации для перемещения по странице.

Чтобы это исправить, установите свойство reading-flow :

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

Теперь порядок фокусировки следующий: один, три, два. Это тот же порядок, который вы бы получили при чтении на английском языке слева направо.

Если же вы предпочитаете сохранить порядок фокусировки в обратном порядке, как это было задумано изначально, вы можете установить:

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

Теперь порядок фокусировки обратный: два, три, один. В обоих случаях учитывается свойство CSS order .

Пример с сеточной компоновкой

Чтобы понять, как это работает в сетке, представьте, что вы создаете макет с помощью CSS-сетки, автоматически размещающей элементы, с двенадцатью областями, на которые можно фокусироваться.

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

Вам нужно, чтобы пятый дочерний элемент занимал самое большое пространство в самом верху, за ним следовал второй дочерний элемент ближе к середине сетки. Все остальные дочерние элементы могут быть автоматически размещены в сетке в соответствии с шаблоном столбца.

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

Попробуйте перемещаться по этим элементам, используя клавишу TAB для поиска следующего элемента, находящегося в фокусе, и клавиши TAB+SHIFT для поиска предыдущего элемента, находящегося в фокусе. Элементы расположены в порядке следования от первого до двенадцатого.

Чтобы это исправить, установите свойство reading-flow :

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

Порядок фокусировки теперь следующий: пять, один, три, два, четыре, шесть, семь, восемь, девять, десять, одиннадцать, двенадцать. Он следует визуальному порядку, строка за строкой.

Если вы хотите, чтобы чтение происходило в соответствии с порядком столбцов, вы можете использовать значение ключевого слова grid-columns . В этом случае порядок фокусировки будет следующим: Пять, Шесть, Девять, Семь, Десять, Один, Два, Одиннадцать, Три, Четыре, Восемь, Двенадцать.

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

Вы также можете попробовать использовать grid-order . Порядок фокусировки остаётся от одного до двенадцати. Это происходит потому, что для ни одного элемента не был задан порядок CSS.

Контейнер блоков, использующий reading-order

Свойство reading-order позволяет указать, когда именно в процессе чтения должен быть посещен тот или иной элемент, переопределяя порядок, заданный свойством reading-flow . Оно действует только в том случае, если свойство reading-flow имеет значение, отличное от normal .

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

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

В следующем блочном контейнере содержится пять элементов. Нет правил компоновки, которые бы изменяли порядок элементов по сравнению с исходным, но есть один элемент, который должен быть просмотрен первым.

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

Установив для этого элемента reading-order равным -1 , порядок фокусировки сначала переходит к нему, а затем возвращается к порядку источника для остальных элементов потока чтения.

Больше примеров вы найдете на сайте chrome.dev .

Взаимодействие с tabindex

Исторически сложилось так, что разработчики использовали глобальный атрибут tabindex в HTML для того, чтобы сделать элементы HTML фокусируемыми и определить относительный порядок для последовательной навигации по фокусу. Однако этот атрибут имеет множество недостатков и проблем с доступностью. Главная проблема заключается в том, что навигация по фокусу, упорядоченная по `tabindex` и созданная с использованием положительного `tabindex`, не распознается деревом доступности. При неправильном использовании это может привести к скачкообразному порядку фокусировки, что не соответствует интерфейсу программ чтения с экрана. Чтобы это исправить, отслеживайте порядок с помощью атрибута `aria-owns` в HTML.

В предыдущем примере с flex-контейнером, чтобы получить тот же результат, что и при использовании reading-flow: flex-visual , можно сделать следующее.

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

Но что произойдет, если у другого элемента вне контейнера также будет tabindex=1 ? Тогда все элементы с tabindex=1 будут посещены одновременно, прежде чем мы перейдем к следующему значению tabindex. Такая прерывистая последовательная навигация приведет к ухудшению пользовательского опыта. Поэтому специалисты по доступности рекомендуют избегать положительных значений tabindex . Мы попытались исправить это при разработке reading-flow .

Контейнер, у которого установлено свойство reading-flow становится владельцем области фокусировки. Это означает, что он ограничивает последовательную навигацию по фокусу таким образом, чтобы перед переходом к следующему фокусируемому элементу в веб-документе посещались все элементы внутри контейнера. Кроме того, его непосредственные дочерние элементы упорядочиваются с помощью свойства reading-flow, а положительные значения tabindex игнорируются для целей упорядочивания. Тем не менее, по-прежнему можно установить положительное значение tabindex для потомков элемента, у которого установлено свойство reading-flow.

Обратите внимание, что элемент с display: contents , наследующий свойство reading-flow от своего родительского элемента макета, также будет являться допустимым контейнером для потока чтения. Учитывайте это при проектировании вашего сайта. Подробнее об этом читайте в нашем запросе на обратную связь по свойствам reading-flow и display: contents .

Дайте нам знать

Попробуйте примеры в этом посте и в примерах reading-flow на chrome.dev , и используйте эти свойства CSS на своих сайтах. Если у вас есть какие-либо замечания, создайте заявку в репозитории GitHub рабочей группы CSS . Если у вас есть замечания конкретно по поведению tabindex и focus scoping, создайте заявку в репозитории GitHub HTML WHATNOT . Мы будем рады вашим отзывам об этой функции.