Семантическая структура страницы
Построим семантический каркас каталога: шапку, навигацию, основную область, карточки и футер.
В первом уроке мы создали документ и вывели один курс. Теперь нужно показать шесть курсов и обозначить отношения между частями страницы. Мы всё ещё не задаём оформление: на этом этапе важно, чтобы исходный порядок можно было прочитать без CSS и понять назначение каждого блока. Красивое расположение не исправляет ошибку в выборе элемента или уровня заголовка.
В каталоге будут курсы о Markdown, техническом SEO, поиске по сайту, деплойменте, дизайне статьи и доступности. Число уроков зафиксируем как двенадцать, двадцать, двадцать, двадцать четыре, двадцать четыре и двадцать. Эти данные не вычисляются браузером: пока они буквально записаны в HTML. Одно и то же содержание мы будем использовать во всех следующих примерах.
Области и порядок чтения
Внутри body заменим прежние заголовки каркасом. В листинге список пока содержит одну карточку; ещё пять нужно добавить как соседние li, используя таблицу ниже. В полном снимке lesson-02 список уже заполнен целиком.
<header class="lab-header">
<div class="lab-shell lab-header-row">
<a class="lab-brand" href="index.html">Профессор Веб · лаборатория</a>
<nav class="lab-nav" aria-label="Основная навигация">
<a href="#courses">Курсы</a>
<a href="#request">Учебная заявка</a>
</nav>
</div>
</header>
<main class="lab-main" id="main">
<div class="lab-shell">
<div class="lab-intro">
<h1 class="lab-title">Учимся создавать сайты</h1>
<p>Выберите курс и последовательно разберите его примеры.</p>
</div>
<section id="courses" aria-labelledby="courses-title">
<h2 id="courses-title">Каталог курсов</h2>
<ul class="course-list">
<li class="course-slot">
<article class="course-card">
<h3 class="course-title">Статический сайт из Markdown</h3>
<p class="course-description">Соберите сайт из текстовых файлов и сохраните постоянные адреса.</p>
<p class="course-meta">
<span class="course-count">12 уроков</span>
<span>Самостоятельное чтение</span>
</p>
</article>
</li>
</ul>
</section>
<p id="request">Учебная форма появится в пятом уроке.</p>
</div>
</main>
<footer class="lab-footer">
<div class="lab-shell lab-footer-row">
<p>layout-lab · учебный пример</p>
<a href="#main">К началу содержимого</a>
</div>
</footer>
Ожидается обычная вертикальная страница: сначала бренд и ссылки, затем главный заголовок, каталог, сообщение о будущей форме и футер. Браузер ещё может показать маркеры списка и привычные поля у заголовков. Это не ошибка выбранной семантики. Позднее уберём маркеры стилями, сохранив связь шести записей как элементов одного списка.
| Курс | Уроков | Описание |
|---|---|---|
| Техническое SEO | 20 | Разберите обнаружение страниц, индексацию и технические ограничения. |
| Поиск по сайту | 20 | Подготовьте индекс материалов и понятную выдачу результатов. |
| Деплоймент | 24 | Подготовьте выпуск, настройте окружение и предусмотрите откат. |
| Дизайн статьи | 24 | Соберите удобную страницу урока с кодом, таблицами и иллюстрациями. |
| Доступность | 20 | Проверьте структуру, клавиатурный маршрут и чтение интерфейса. |
Что выражают выбранные элементы
header относится к вводной части страницы, nav объединяет основные переходы, а main обозначает главное содержимое. В нашем документе одна видимая основная область. Футер содержит сведения о примере и обратный переход. Смысл main и ограничения его использования приведены в MDN. Эти элементы помогают описать документ, но не обещают конкретного расположения на экране.
Карточка курса использует article, потому что представляет отдельную содержательную единицу: название, описание и метаданные. Список сообщает, что таких единиц несколько. Дополнительная обёртка li не заменяет карточку: она выражает участие записи в списке. В пятнадцатом уроке эта же обёртка станет контейнером для локального адаптивного правила, и структура позволит добавить поведение без переписывания содержимого.
Не каждую обёртку нужно делать section. У вводного блока уже есть главный заголовок, но его вспомогательная оболочка служит компоновке, поэтому здесь достаточно div. Раздел каталога, напротив, имеет собственную тему и название. Имена lab-shell и lab-header-row пока ничего не отображают. Мы дали их тем узлам, для которых позднее понадобится ширина или расположение; это подготовка селекторов, а не новая семантика.
Два span внутри метаданных сохраняют части одной строки. Они нужны, чтобы можно было отдельно выбрать число уроков и пояснение. Не нужно заменять каждый короткий фрагмент div, если вы не вводите отдельный блок. Решение зависит от роли в документе. Когда CSS изменит расположение этих фрагментов, содержание всё равно останется одной группой метаданных.
Уровни заголовков и связи
Главный заголовок сообщает тему страницы. Второй уровень вводит каталог. Каждая запись использует третий уровень, поскольку находится внутри этого раздела. Мы не выбирали h3 ради его меньшего размера: CSS может сделать его крупнее второго уровня. При добавлении нового раздела после каталога, например заявки, у него будет свой заголовок второго уровня. Внутри формы не требуется ещё один главный заголовок.
aria-labelledby связывает раздел с уже видимым заголовком. Значение должно точно совпасть с id этого заголовка. Сам id должен быть уникальным в документе. Не копируйте courses-title внутрь всех карточек: повторяющиеся идентификаторы делают связи неоднозначными. Одинаковый класс карточек допустим и полезен, одинаковый идентификатор разных элементов — другой случай.
У навигации мы указали короткое имя. Оно позволяет отличить эту область, если позднее появятся дополнительные переходы. Не нужно автоматически писать одинаковый aria-label на каждом блоке: имя должно помогать различать смысл. Более подробное объяснение семантики и чтения структуры уже есть в уроке о доступной разметке; здесь мы используем эти основы для механики каталога.
Почему структура предшествует сетке
Если сейчас открыть документ без стилей, шесть записей должны идти в осмысленном порядке и каждая иметь название, описание, число уроков. Это исходная последовательность. Позднее Grid распределит записи по колонкам, но мы не будем перемещать их ради случайной зрительной симметрии. Порядок HTML остаётся важным и для обычного чтения, и для перехода по ссылкам.
Попробуйте добавить седьмой курс в конец списка. Ожидается новая соседняя запись без изменений в каркасе. Затем перенесите футер внутрь карточки и сравните дерево: такой футер уже будет относиться к карточке, а не ко всей странице. Внешне без CSS разница может быть почти незаметна, но структура изменилась. Умение видеть эту разницу поможет отделять семантику от будущего оформления.
При копировании карточек сохраняйте границы элементов списка. Следующий li должен стать соседом предыдущего, а не его вложенной частью. Иначе внешне похожая запись превратится в часть другой записи, а будущая сетка выберет меньше непосредственных детей, чем вы ожидаете. Число тегов article само по себе не подтверждает правильность списка. Посмотрите уровень вложенности и закрытие каждого элемента.
Также не добавляйте в карточки собственный main. Основное содержимое относится к документу целиком, а курс внутри каталога является частью этой области. Повторяющиеся карточки могут иметь свои заголовки и дополнительные сведения, но не должны каждая объявлять себя отдельным главным содержимым той же страницы. Разметка выражает отношения, а не количество визуально крупных блоков.
Список выбран потому, что записи образуют перечисление, а не табличное сравнение одних и тех же показателей по строгим столбцам. Внешняя сетка из трёх колонок позднее не превратит его автоматически в таблицу. Если задача изменится и появятся сравнимые характеристики курсов, таблица может стать подходящей новой структурой. Тип HTML определяется отношениями данных, а не количеством визуальных колонок, которое случайно помещается в окне.
После этого шага содержание больше не зависит от одного абзаца. Есть повторяемая единица, общий список и ясные границы страницы. Следующий урок добавит к названиям рабочие переходы и разберёт, почему похожие записи адресов могут вести в разные места при переносе файла.