Переполнение и прокрутка
Текстовый каталог хорошо помещается в несколько столбцов, но таблица сравнения может требовать больше ширины, чем доступно на телефоне. Если просто спрятать выходящую часть, читатель потеряет столбцы. Если позволить таблице расширять весь документ, горизонтально двигаться начнут и заголовки, и форма. Локальное управление переполнением сохраняет доступ к широкой информации внутри понятной области.
Продолжим страницу с закрепляемой навигацией. Добавим таблицу тех же шести курсов, сохраняя названия, количества и реальные адреса. Результат урока — отдельная горизонтально прокручиваемая область. У неё есть подпись, видимая инструкция и возможность получить клавиатурный фокус; это исходная модель для последующей ручной проверки, а не готовый отчёт о доступности.
Широкое содержание и ограниченная оболочка
Таблица имеет структуру заголовков столбцов и строк. Её смысл не должен зависеть от положения текста по случайным пикселям. Поэтому сохраняем table, caption, th и td, а прокрутку назначаем внешней коробке. Дисплей самой таблицы не заменяем на декоративный набор блоков: ширина и прокрутка не требуют разрушения исходных связей.
В index.html вставьте следующий полный блок после закрывающего тега секции courses, перед секцией учебной заявки. Он находится за пределами контейнера sticky-навигации, поэтому навигация курсов уже не должна сопровождать его при дальнейшей прокрутке. Идентификаторы новой секции уникальны.
<section class="lab-comparison" aria-labelledby="comparison-title">
<h2 id="comparison-title">Сравнение курсов</h2>
<p id="comparison-note">На узком экране прокрутите таблицу по горизонтали.</p>
<div class="lab-table-scroll" tabindex="0" role="region" aria-labelledby="comparison-title" aria-describedby="comparison-note">
<table>
<caption>Те же шесть учебных маршрутов</caption>
<thead>
<tr>
<th scope="col">Курс</th>
<th scope="col">Уроков</th>
<th scope="col">Формат</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/static-site-markdown/">Статический сайт из Markdown</a>
</th>
<td>12</td>
<td>Самостоятельное чтение примеров</td>
</tr>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/technical-seo/">Техническое SEO</a>
</th>
<td>20</td>
<td>Самостоятельное чтение примеров</td>
</tr>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/site-search/">Поиск по сайту</a>
</th>
<td>20</td>
<td>Самостоятельное чтение примеров</td>
</tr>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/web-deployment/">Деплоймент</a>
</th>
<td>24</td>
<td>Самостоятельное чтение примеров</td>
</tr>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/article-design/">Дизайн статьи</a>
</th>
<td>24</td>
<td>Самостоятельное чтение примеров</td>
</tr>
<tr>
<th scope="row">
<a href="https://professorweb.ru/courses/web-accessibility/">Доступность</a>
</th>
<td>20</td>
<td>Самостоятельное чтение примеров</td>
</tr>
</tbody>
</table>
</div>
</section>
В конец styles.css добавьте следующий полный блок. Он задаёт отдельную границу переполнения и минимальную ширину содержимого таблицы, не меняя ширину всей оболочки страницы.
@layer components {
.layout-lab .lab-comparison { margin-block-start: 2rem; }
.layout-lab .lab-table-scroll { max-inline-size: 100%; overflow-x: auto; padding: .5rem; margin-block-start: 1rem; border: 1px solid var(--lab-line); }
.layout-lab table { inline-size: 100%; min-inline-size: 42rem; border-collapse: collapse; }
.layout-lab caption { text-align: start; margin-block-end: .5rem; }
.layout-lab th, .layout-lab td { padding: .75rem; text-align: start; border-block-end: 1px solid var(--lab-line); }
}
На широком экране ожидается таблица, занимающая доступную ширину. На более узком, чем её выбранный минимум, ожидается горизонтальное движение внутри рамки. Заголовок секции и пояснение остаются вне этой движущейся коробки. Форма ниже должна сохранять прежнее положение и не расширяться до ширины таблицы.
Различные значения overflow
При visible содержимое может рисоваться за пределами коробки без появления собственного прокручиваемого контейнера. При auto браузер позволяет прокрутку, когда переполнение действительно требуется. scroll задаёт механизм прокрутки независимо от наличия лишнего содержимого, хотя конкретный вид полос зависит от системы. Поэтому наличие или отсутствие постоянно видимой полосы нельзя использовать как единственное доказательство доступности скрытой части.
hidden обрезает видимую часть и не показывает обычную полосу, но такой контейнер может прокручиваться программно или вследствие перехода к скрытому фокусируемому потомку. Значение clip тоже обрезает, однако не создаёт тот же прокручиваемый механизм. Для таблицы оба варианта неудобны, если они лишают читателя понятного способа добраться до столбцов. Обрезание подходит иной обязанности, например чисто декоративному краю изображения.
В нашем основном правиле настроена горизонтальная ось overflow-x. У двух физических осей есть взаимодействие вычисленных значений: сочетание прокручиваемого значения по одной оси с visible по другой может преобразовать второе в auto. Поэтому это не обещание, что вертикальная сторона останется буквально visible в computed-стиле. Мы не ограничиваем высоту таблицы, и её строки могут занять необходимое место по вертикали.
Разница прокручиваемой коробки и простого обрезания описана в MDN об overflow. В данном документе строки горизонтальные, поэтому физическая ось X совпадает с шириной таблицы. При настоящем вертикальном письме такой выбор следовало бы разобрать отдельно; логические отступы предыдущих уроков не переводят каждое физическое свойство автоматически.
Размер содержимого и причина прокрутки
Минимум 42rem выбран как учебное ограничение, позволяющее увидеть широкий набор трёх столбцов. Он не получен измерением нашего контента во всех шрифтах. При необходимости проект должен выбрать минимум по реальной читаемости названий и подписей. Слишком большой минимум создаст лишнюю прокрутку, а слишком маленький может превратить таблицу в набор неудобных высоких узких ячеек.
Значение inline-size: 100% делает таблицу шириной доступной области, когда та достаточно велика. min-inline-size препятствует дальнейшему сжатию ниже выбранного размера. Противоречие между внешней шириной и внутренним минимумом здесь намеренное: его разрешает прокручиваемая обёртка. Это отличается от случайного переполнения, которое автор пытается спрятать на body.
Не добавляйте overflow-x: hidden всему документу ради исчезновения горизонтальной полосы окна. Такое правило способно скрыть ошибку другого элемента и лишить доступа к его содержимому. В учебной странице мы сначала ищем широкую коробку, затем задаём ей локальную область. Карточки и форма остаются адаптивными по своим правилам и не должны зависеть от глобального обрезания.
Фокус и видимая инструкция
Обёртка получила tabindex="0", чтобы возможность фокуса не зависела исключительно от того, делает ли конкретный браузер прокручиваемые области фокусируемыми автоматически. role="region" вместе с именем заголовка поясняет её назначение, а aria-describedby связывает инструкцию. Эти атрибуты помогают обозначить коробку, но не проверяют её фактическую прокрутку и не исправляют потерянные заголовки таблицы.
Стандартное правило :focus-visible уже включает элементы с tabindex, поэтому рамка фокуса должна быть заметна. Внутренний небольшой отступ отделяет содержимое от края. Следует позже проверить, что фокус отдельных ссылок тоже остаётся видимым и браузер показывает нужный столбец, когда читатель переходит к ссылке. Ожидаемое поведение нужно смотреть в выбранных браузерах и со вспомогательными средствами.
Не назначайте tabindex каждой ячейке только для возможности прокрутки. Тогда клавиатурный маршрут получит множество остановок без самостоятельного действия. Настоящие ссылки в названиях уже имеют собственную роль, а внешняя область даёт одну дополнительную точку управления широким содержимым. Количество фокусируемых узлов должно следовать обязанностям интерфейса, а не числу видимых прямоугольников.
Проверка ограничения без потери строк
Для диагностического опыта временно замените overflow-x: auto на hidden. На узком окне ожидается обрезанная часть таблицы без обычного способа горизонтальной прокрутки. Затем восстановите auto. Этот опыт показывает цену визуально аккуратной границы: всё содержание может оставаться в DOM, но быть неудобно доступным на экране.
Также временно уберите минимальную ширину таблицы. Ожидается больше переносов и возможное исчезновение потребности в горизонтальном движении. Это не обязательно лучший макет: нужно оценить высоту строк и читаемость сопоставления. Затем верните учебный минимум, чтобы следующее состояние серии совпадало с сохранённым снимком. Не смешивайте обе диагностические правки в один вывод.
В печатной версии собственное узкое окно обычно не нужно. Окончательный урок отдельно уточнит вывод таблицы: её размер не должен оставлять печатные столбцы за невидимой прокручиваемой рамкой. Пока мы получили исходную интерактивную область и объяснили причину её ширины. Следующий урок применит движение к ленте карточек и добавит предпочтительные места остановки.
Полное состояние этого шага находится в layout-lab/lesson-25 внутри исходников продолжения. Каждый снимок открывается отдельно; подключать CSS разных уроков одновременно не нужно.