Что такое порядок табуляции — и почему CSS его не переставляет

Ты поменял местами две колонки одной строкой CSS: flex-direction: row-reverse. На экране всё отлично — текст слева, форма справа. А потом кто-то жмёт Tab. Фокус сначала прыгает вправо, в форму, потом возвращается влево, к ссылкам в тексте. Страница будто перепутана.
Она и перепутана — только не на экране. Клавиатура не смотрит на картинку. Она идёт по порядку HTML-кода. Этот порядок и называют порядком табуляции.
Что такое порядок табуляции
Это очередь элементов, по которым проходит клавиша Tab. Shift+Tab идёт по той же очереди назад.
В очередь сами попадают элементы, с которыми можно что-то сделать:
- ссылки с атрибутом
href; - кнопки, поля ввода, выпадающие списки,
textarea; summary— заголовок раскрывающегося блокаdetails.
Обычный текст, картинки, div и span в очередь не попадают. На них Tab не остановится.
Кто ходит по этой очереди? Люди, которые не пользуются мышью. Незрячие со скринридером. И просто все, кто быстро заполняет форму: Tab — следующее поле, Tab — ещё одно.
Как браузер строит очередь
Правило одно, и оно простое: порядок элементов в HTML. Сверху вниз по разметке. Руководство WCAG так и пишет: без скриптов и tabindex порядок навигации совпадает с порядком в коде.
Отсюда ловушка из начала статьи. CSS двигает только картинку. Где элемент нарисован — меняется. Где он стоит в очереди — нет. Так работают:
orderу элементов флекса или грида;flex-direction: row-reverseиcolumn-reverse;- ручная расстановка по ячейкам грида;
position: absolute, которым элемент утащили в другой угол.
MDN прямо предупреждает про order: он создаёт разрыв между тем, что видно, и тем, что в DOM. Человек с мышью видит одну страницу, человек с клавиатурой — другую.
<div class="row">
<form>…</form>
<aside>…</aside>
</div>
.row { display: flex; flex-direction: row-reverse; }
На экране aside стоит слева. Но в коде форма первая — значит, Tab сначала поведёт в неё.
Три значения tabindex
Атрибут tabindex управляет очередью вручную. Безопасны только два значения из трёх.
tabindex="0"— добавить в очередь элемент, которого там нет. Он встанет на своё место по HTML. Нужно редко: если элемент интерактивный, лучше сразу взять<button>.tabindex="-1"— Tab на элемент не встанет, но скрипт может поставить на него фокус черезfocus(). Так делают с открывшимся модальным окном или с сообщением об ошибке после отправки формы.tabindex="1"и больше — вытащить элемент в начало очереди. MDN советует не использовать положительные значения вовсе.
Почему положительные — зло? Элемент с tabindex="1" обгоняет все элементы страницы с нулём. Поставил его одному полю формы — и оно окажется раньше логотипа, меню и поиска. А если таких номеров несколько, их придётся вручную поддерживать по всему сайту.
Проблема растёт. По отчёту WebAIM за 2026 год, на главной странице в среднем 30,4 атрибута tabindex со значением 0 или -1. С 2020 года — почти в четыре раза больше.
Как починить порядок, а не замаскировать
- Расставь элементы в HTML так, как их нужно читать. Сначала смысл в коде, потом раскладка в CSS. Двигать картинку можно, но так, чтобы она не спорила с кодом.
- Проверь медиазапросы. Частая история: на телефоне блоки переставили через
order, и Tab на мобильной версии прыгает. Подробнее про мобильную раскладку — в гайде как сделать сайт удобным на телефоне. - Не лечи
tabindex="1". Положительные номера маскируют проблему в одном месте и создают её в другом. - Присмотрись к
reading-flow. Это новое CSS-свойство:reading-flow: flex-visualвелит вести Tab и скринридер по визуальному порядку флекса. Оно есть в Chrome с версии 137, а в Firefox и Safari пока нет. Так что это запасной вариант, а не основа.
Проверка за полминуты: убери руку с мыши и нажми Tab раз десять. Фокус должен идти так, как ты читаешь, — слева направо и сверху вниз. Не видно, где фокус, вообще? Это отдельная поломка: почему пропала рамка фокуса.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.
Почему Tab на Mac не переходит по ссылкам?
Это настройка, а не баг. В Safari по умолчанию Tab ходит только по полям форм. Для ссылок жми Option+Tab или включи в настройках Safari, раздел «Дополнительно», пункт про выделение каждого объекта на веб-странице клавишей Tab.
Почему Tab не заходит в мой div с onclick?
Потому что div нет в очереди. Замени его на <button type="button"> — он встанет в очередь и будет нажиматься Enter и пробелом без лишнего кода.
Можно ли убрать элемент из очереди Tab?
Можно: tabindex="-1" убирает один элемент, а атрибут inert делает неактивным целый блок, например страницу под открытой модалкой. Но не прячь так то, что видно и кликается мышью: человек с клавиатурой до этого просто не доберётся.





