Опубликовано: 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 . Мы будем рады вашим отзывам об этой функции.