HTML & CSS

Списки та таблиці в HTML

Детальний розбір елементів <ul>, <ol>, <dl>, <table>, <caption>, <colgroup> за специфікацією HTML Living Standard: семантика, доступність, colspan/rowspan та коли використовувати таблиці.

Списки та таблиці в HTML

Чому структура важливіша за вигляд

Уявіть бібліотекаря, якому поставили завдання розставити книги. Є два підходи: перший каже «поставте ці книги на цю полицю», другий — «це серія детективів, вони мають стояти разом у алфавітному порядку». Другий підхід несе змісту більше, ніж перший.

Саме так працює семантика в HTML. Елементи <ul>, <ol>, <dl>, <table> — це не просто спосіб відобразити список чи сітку. Це спосіб передати значення браузеру, пошуковику та скринрідеру: «це перелік рівноцінних речей», «це послідовність кроків», «це структуровані дані з відношеннями між рядками і стовпцями».

Сьогодні розберемо ці елементи так, як їх визначає HTML Living Standard (WHATWG).


Ненумерований список — <ul>

Що каже специфікація

<ul> (unordered list — ненумерований список) представляє список елементів, порядок яких не є значущим. Зміна порядку елементів не впливає на зміст.

За специфікацією WHATWG:

  • Content model: нуль або більше елементів <li>, опційно з <script> та <template>
  • Permitted parents: будь-який елемент, що приймає flow content
<!-- ✅ Правильно: порядок тут не важливий -->
<ul>
    <li>Молоко</li>
    <li>Хліб</li>
    <li>Яйця</li>
</ul>

<!-- ✅ Навігація — класичне застосування <ul> -->
<nav aria-label="Категорії товарів">
    <ul>
        <li><a href="/electronics">Електроніка</a></li>
        <li><a href="/clothing">Одяг</a></li>
        <li><a href="/books">Книги</a></li>
    </ul>
</nav>
ul {
    list-style-type: square;
    color: #3b82f6;
    padding-left: 1.5rem;
}
nav ul {
    list-style-type: none;
    padding: 0;
    display: flex;
    gap: 1rem;
}
nav a {
    text-decoration: none;
    color: #111;
    font-weight: 500;
}
nav a:hover {
    text-decoration: underline;
    color: #ef4444;
}
Preview
Коли використовувати <ul>: коли елементи є рівноцінними і не мають чіткого порядку — навігаційні меню, списки тегів, переліки переваг, інгредієнти рецепту.

Вкладені списки

<ul> можна вкладати один в одного для ієрархічних структур. Важливо: вкладений список завжди знаходиться всередині <li>, а не після нього.

<!-- ✅ Правильно: вкладений список всередині <li> -->
<ul>
    <li>
        Фрукти
        <ul>
            <li>Яблука</li>
            <li>Груші</li>
            <li>
                Цитрусові
                <ul>
                    <li>Апельсини</li>
                    <li>Лимони</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Овочі</li>
</ul>

<!-- ❌ Неправильно: вкладений список після </li> -->
<ul>
    <li>Фрукти</li>
    <ul>
        <li>Яблука</li>
    </ul>
</ul>
ul {
    background-color: #f9fafb;
    padding: 1rem 1rem 1rem 2.5rem;
    border-radius: 0.5rem;
    margin-bottom: 1rem;
}
ul ul {
    background-color: #f3f4f6;
    margin-bottom: 0;
    margin-top: 0.5rem;
}
Preview

Нумерований список — <ol>

Що каже специфікація

<ol> (ordered list — нумерований список) представляє список елементів, порядок яких є значущим. Зміна порядку елементів змінює зміст.

Атрибути <ol>:

АтрибутТипОпис
startчислоПочаткове значення лічильника (за замовч. 1)
reversedбулевийЗворотний відлік
typeрядокТип маркера: 1, a, A, i, I
<!-- Звичайна нумерація -->
<ol>
    <li>Відкрити термінал</li>
    <li>Перейти у директорію проєкту</li>
    <li>Виконати npm install</li>
    <li>Запустити npm run dev</li>
</ol>

<!-- Починаємо не з 1 -->
<ol start="5">
    <li>П'ятий крок</li>
    <li>Шостий крок</li>
</ol>

<!-- Зворотній відлік (наприклад, топ-3) -->
<ol reversed>
    <li>Третє місце — Олена Мороз</li>
    <li>Друге місце — Ігор Лисенко</li>
    <li>Перше місце — Марія Коваль</li>
</ol>

<!-- Літерна нумерація -->
<ol type="a">
    <li>Перший варіант відповіді</li>
    <li>Другий варіант відповіді</li>
    <li>Третій варіант відповіді</li>
</ol>

<!-- Римські цифри -->
<ol type="I">
    <li>Вступ</li>
    <li>Основна частина</li>
    <li>Висновки</li>
</ol>
ol {
    font-family: ui-sans-serif, system-ui, sans-serif;
    margin-bottom: 2rem;
    padding-left: 2rem;
}
li {
    padding: 0.2rem 0;
}
li::marker {
    color: #8b5cf6;
    font-weight: bold;
}
Preview

Атрибут value у <li>

Кожен <li> всередині <ol> може мати свій value, що змінює лічильник:

<ol>
    <li value="10">Десятий пункт</li>
    <li>Одинадцятий пункт</li>
    <!-- автоматично 11 -->
    <li value="20">Двадцятий пункт</li>
    <li>Двадцять перший пункт</li>
    <!-- автоматично 21 -->
</ol>
Коли використовувати <ol>: покрокові інструкції, рецепти (послідовність дій), рейтинги, юридичні документи, пронумеровані розділи — скрізь, де порядок несе змістовне навантаження.

Список визначень — <dl>, <dt>, <dd>

Що каже специфікація

<dl> (description list — список описів) представляє асоціативні пари: назва → опис. Це не просто «словник» — специфікація WHATWG описує <dl> як список груп, де кожна група містить:

  • Один або більше <dt> (description term — термін)
  • Один або більше <dd> (description definition — визначення)
<!-- Класичне застосування: глосарій -->
<dl>
    <dt>HTML</dt>
    <dd>HyperText Markup Language — мова розмітки гіпертексту, основа веб-сторінок.</dd>

    <dt>CSS</dt>
    <dd>Cascading Style Sheets — мова стилів для оформлення HTML-документів.</dd>

    <dt>JavaScript</dt>
    <dd>Мова програмування для інтерактивності у браузері.</dd>
</dl>

<!-- Один термін — кілька визначень -->
<dl>
    <dt>Банк</dt>
    <dd>Фінансова установа, що зберігає кошти клієнтів.</dd>
    <dd>Берег річки (у деяких контекстах).</dd>
</dl>

<!-- Кілька термінів — одне визначення -->
<dl>
    <dt>Frontend</dt>
    <dt>Front-end</dt>
    <dt>UI-розробник</dt>
    <dd>Спеціаліст, що розробляє клієнтську частину веб-застосунків.</dd>
</dl>
dl {
    background: white;
    padding: 1.5rem;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    margin-bottom: 2rem;
}
dt {
    font-weight: 700;
    color: #1f2937;
    margin-top: 1rem;
}
dt:first-child {
    margin-top: 0;
}
dd {
    margin-left: 0;
    padding-left: 1rem;
    border-left: 3px solid #60a5fa;
    color: #4b5563;
    margin-top: 0.5rem;
}
Preview

Реальні застосування <dl>

<article>
    <h1>Огляд фреймворку Vue 3</h1>

    <dl>
        <dt>Автор</dt>
        <dd><a href="/authors/ivan-koval">Іван Коваль</a></dd>

        <dt>Опубліковано</dt>
        <dd><time datetime="2024-11-15">15 листопада 2024</time></dd>

        <dt>Категорія</dt>
        <dd><a href="/categories/frontend">Frontend</a></dd>

        <dt>Час читання</dt>
        <dd>8 хвилин</dd>
    </dl>
</article>
Типова помилка: використання <dl> для будь-яких пар «ключ-значення», навіть коли структура не є списком визначень. Якщо вміст — це просто два стовпці даних — вірніше використати <table>.

Таблиці — <table>

Коли таблиця є правильним вибором

Таблиця — не інструмент макетування. Це семантичний спосіб представлення табличних даних: інформації, яка має значущі відносини між рядками та стовпцями.

✅ Таблиці підходять для

  • Розклади (уроків, рейсів, сеансів)
  • Порівняльні характеристики продуктів
  • Фінансові звіти, тарифи
  • Статистика, результати змагань
  • Будь-які дані з чітким заголовком рядка/стовпця

❌ Таблиці НЕ підходять для

  • Верстка макету сторінки (header/sidebar/footer)
  • Вирівнювання форм
  • Відображення списків у кілька колонок
  • Будь-що, що можна зробити через CSS Grid або Flexbox

Базова структура таблиці

<table>
    <tr>
        <th>Назва</th>
        <th>Ціна</th>
        <th>Кількість</th>
    </tr>
    <tr>
        <td>Ноутбук</td>
        <td>35 000 грн</td>
        <td>5</td>
    </tr>
    <tr>
        <td>Мишка</td>
        <td>800 грн</td>
        <td>20</td>
    </tr>
</table>
table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 1rem;
    font-family: ui-sans-serif, system-ui, sans-serif;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
th,
td {
    border: 1px solid #e5e7eb;
    padding: 0.75rem 1rem;
    text-align: left;
}
th {
    background-color: #f3f4f6;
    font-weight: 600;
    color: #374151;
}
tr:nth-child(even) {
    background-color: #f9fafb;
}
tr:hover {
    background-color: #f3f4f6;
}
Preview

Але це лише мінімум. Специфікація WHATWG визначає значно багатшу модель.


Анатомія таблиці: всі елементи

<caption> — підпис таблиці

<caption>перший дочірній елемент <table>, що задає її назву. Доступний як для зрячих, так і для скринрідерів:

<table>
    <caption>
        Порівняння тарифних планів на хостинг
    </caption>
    <!-- ... -->
</table>
<caption> еквівалентний <figcaption> для зображень. Без нього таблиця може бути незрозумілою поза контекстом.

<thead>, <tbody>, <tfoot> — семантичне групування

Специфікація визначає три секції таблиці:

<table>
    <caption>
        Фінансовий звіт Q4 2024
    </caption>

    <thead>
        <!-- Заголовки стовпців -->
        <tr>
            <th scope="col">Місяць</th>
            <th scope="col">Дохід</th>
            <th scope="col">Витрати</th>
            <th scope="col">Прибуток</th>
        </tr>
    </thead>

    <tbody>
        <!-- Основні дані -->
        <tr>
            <th scope="row">Жовтень</th>
            <td>125 000 грн</td>
            <td>87 000 грн</td>
            <td>38 000 грн</td>
        </tr>
        <tr>
            <th scope="row">Листопад</th>
            <td>143 000 грн</td>
            <td>91 000 грн</td>
            <td>52 000 грн</td>
        </tr>
        <tr>
            <th scope="row">Грудень</th>
            <td>198 000 грн</td>
            <td>105 000 грн</td>
            <td>93 000 грн</td>
        </tr>
    </tbody>

    <tfoot>
        <!-- Підсумки -->
        <tr>
            <th scope="row">Разом Q4</th>
            <td>466 000 грн</td>
            <td>283 000 грн</td>
            <td>183 000 грн</td>
        </tr>
    </tfoot>
</table>
table {
    width: 100%;
    border-collapse: collapse;
    font-family: ui-sans-serif, system-ui, sans-serif;
    margin-top: 1rem;
}
caption {
    caption-side: top;
    font-weight: bold;
    font-size: 1.125rem;
    margin-bottom: 0.5rem;
    color: #1f2937;
    text-align: center;
}
th,
td {
    border: 1px solid #e5e7eb;
    padding: 0.75rem 1rem;
}
thead th {
    background-color: #f3f4f6;
    border-bottom: 2px solid #d1d5db;
    text-align: left;
}
tbody th {
    background-color: #f9fafb;
    text-align: left;
    font-weight: 500;
}
tfoot th,
tfoot td {
    background-color: #e5e7eb;
    font-weight: bold;
    border-top: 2px solid #9ca3af;
}
td {
    text-align: right;
    font-variant-numeric: tabular-nums;
}
Preview

Навіщо розділяти <thead>/<tbody>/<tfoot>:

  • Браузер може прокручувати тіло таблиці незалежно, зберігаючи заголовки видимими
  • При друці заголовки та підвал повторюються на кожній сторінці
  • Скринрідери правильно визначають роль кожної секції

<th> vs <td> — заголовок vs дані

<th> (table header) — заголовкова комірка. <td> (table data) — комірка з даними.

Ключовий атрибут <th>scope:

scopeЗначення
colЗаголовок для всього стовпця
rowЗаголовок для всього рядка
colgroupЗаголовок для групи стовпців
rowgroupЗаголовок для групи рядків
<!-- scope="col" — заголовок стовпця -->
<thead>
    <tr>
        <th scope="col">Товар</th>
        <th scope="col">Ціна</th>
    </tr>
</thead>

<!-- scope="row" — заголовок рядка -->
<tbody>
    <tr>
        <th scope="row">Ноутбук Dell XPS 13</th>
        <td>42 000 грн</td>
    </tr>
</tbody>
Завжди вказуйте scope для <th>. Це вирішальний атрибут для доступності: скринрідер оголошує «Ціна: 42 000 грн» замість просто «42 000 грн».

<colgroup> та <col> — групування стовпців

<colgroup> (column group) та <col> (column) дозволяють стилізувати або ідентифікувати цілі стовпці без повторення атрибутів у кожній комірці.

<table>
    <caption>
        Розклад занять
    </caption>

    <colgroup>
        <!-- Перший стовпець (час) -->
        <col />
        <!-- Три стовпці аудиторій -->
        <col span="3" />
        <!-- Стовпець перерви -->
        <col />
    </colgroup>

    <thead>
        <tr>
            <th scope="col">Час</th>
            <th scope="col">Аудиторія 101</th>
            <th scope="col">Аудиторія 102</th>
            <th scope="col">Аудиторія 103</th>
            <th scope="col">Перерва</th>
        </tr>
    </thead>
    <!-- ... -->
</table>
table {
    width: 100%;
    border-collapse: collapse;
    font-family: ui-sans-serif, system-ui, sans-serif;
}
th,
td {
    border: 1px solid #e5e7eb;
    padding: 0.5rem;
    text-align: center;
}
thead th {
    background-color: #f3f4f6;
}
/* Style via colgroup */
col:first-child {
    background-color: #f9fafb;
    font-weight: 500;
}
col[span='3'] {
    background-color: #eff6ff; /* light blue for auditoriums */
}
col:last-child {
    background-color: #fef2f2; /* light red for breaks */
}
Preview
<colgroup> та <col> — у першую чергу механізм для застосування CSS-стилів до цілого стовпця (через клас або атрибут style). Пряме стилізування через <col> підтримує лише обмежений набір CSS-властивостей: width, visibility, background, border.

colspan та rowspan — об'єднання комірок

colspan — об'єднання стовпців

<table class="simple-table">
    <thead>
        <tr>
            <th scope="col" rowspan="2">Предмет</th>
            <th scope="colgroup" colspan="2">Оцінки</th>
        </tr>
        <tr>
            <th scope="col">Контрольна</th>
            <th scope="col">Іспит</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Математика</th>
            <td>92</td>
            <td>88</td>
        </tr>
        <tr>
            <th scope="row">Фізика</th>
            <td>78</td>
            <td>85</td>
        </tr>
    </tbody>
</table>
.simple-table {
    border-collapse: collapse;
    font-family: ui-sans-serif, system-ui, sans-serif;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    background: white;
}
.simple-table th,
.simple-table td {
    border: 1px solid #d1d5db;
    padding: 0.5rem 1rem;
    text-align: center;
}
.simple-table th {
    background-color: #f3f4f6;
}
Preview

rowspan — об'єднання рядків

<table class="schedule-table">
    <caption>
        Розклад конференції
    </caption>
    <thead>
        <tr>
            <th scope="col">Час</th>
            <th scope="col">Зал A</th>
            <th scope="col">Зал B</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">09:00–09:45</th>
            <!-- Ця доповідь займає обидва зали — colspan="2" -->
            <td colspan="2" class="highlight">Відкриття конференції та вітальне слово</td>
        </tr>
        <tr>
            <th scope="row">10:00–10:45</th>
            <td>Vue.js 4: що нового</td>
            <td>TypeScript для початківців</td>
        </tr>
        <tr>
            <!-- Цей часовий блок займає два рядки — rowspan="2" -->
            <th scope="row" rowspan="2" class="time-block">11:00–12:30</th>
            <td class="workshop">Воркшоп з React</td>
            <td class="workshop">Воркшоп з Node.js</td>
        </tr>
        <tr>
            <!-- Немає th — час вже займає попередній рядок -->
            <td>Архітектура мікросервісів</td>
            <td>Performance у браузері</td>
        </tr>
    </tbody>
</table>
.schedule-table {
    border-collapse: collapse;
    font-family: ui-sans-serif, system-ui, sans-serif;
    width: 100%;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    background: white;
}
.schedule-table caption {
    font-weight: bold;
    font-size: 1.2rem;
    padding-bottom: 0.5rem;
}
.schedule-table th,
.schedule-table td {
    border: 1px solid #d1d5db;
    padding: 0.75rem;
    text-align: center;
}
.schedule-table thead th {
    background-color: #4b5563;
    color: white;
}
.schedule-table tbody th {
    background-color: #f3f4f6;
    white-space: nowrap;
}
.highlight {
    background-color: #fef08a; /* Yellow */
    font-weight: bold;
}
.time-block {
    background-color: #e5e7eb !important;
}
.workshop {
    background-color: #bfdbfe; /* Blue */
}
Preview
colspan та rowspan роблять таблицю складнішою для скринрідерів. Якщо об'єднання комірок обов'язкове — завжди доповнюйте таблицю атрибутами scope, id/headers для правильної прив'язки.

Зв'язок через id та headers для складних таблиць

Для дуже складних таблиць (з багаторівневими заголовками) scope недостатньо. Використовують id + headers:

<table>
    <thead>
        <tr>
            <th id="city" scope="colgroup" colspan="2">Місто</th>
            <th id="temp" scope="colgroup" colspan="2">Температура (°C)</th>
        </tr>
        <tr>
            <th id="city-name" headers="city">Назва</th>
            <th id="city-region" headers="city">Регіон</th>
            <th id="temp-min" headers="temp">Мін.</th>
            <th id="temp-max" headers="temp">Макс.</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td headers="city city-name">Київ</td>
            <td headers="city city-region">Київська обл.</td>
            <td headers="temp temp-min">-15</td>
            <td headers="temp temp-max">+32</td>
        </tr>
    </tbody>
</table>

Атрибут <li>: елемент списку

<li> (list item) — елемент списку. Використовується всередині <ul>, <ol> та застарілого <menu>.

Атрибут value у <ol> (уже показаний вище) та відсутність атрибутів у <ul> — це вся специфіка <li>. Зверніть увагу: <li> як block-level елемент може містити будь-який flow content — параграфи, зображення, вкладені списки:

<ul>
    <li>
        <!-- <li> може містити блокові елементи -->
        <h3>JavaScript</h3>
        <p>Мова програмування для вебу.</p>
        <ul>
            <li>Node.js</li>
            <li>React</li>
            <li>Vue.js</li>
        </ul>
    </li>
</ul>

Підсумкові таблиці атрибутів

Атрибути <ol>

start
number
Початкове число лічильника. За замовчуванням 1. Завжди є цілим числом, навіть якщо type="a".
reversed
boolean
Відлік у зворотному порядку. Браузер відображає числа від start до 1 (або нижче).
type
string
Вибір маркера: 1 (числа), a (рядкові), A (великі), i (римські рядкові), I (римські великі).

Атрибути <li> в <ol>

value
number
Перевизначає поточне значення лічильника для цього елемента і всіх наступних.

Атрибути <table> та комірок

colspan
number
Кількість стовпців, що охоплює комірка (<td> або <th>). За замовч. 1.
rowspan
number
Кількість рядків, що охоплює комірка. За замовч. 1. Значення 0 — від поточного рядка до кінця секції (thead/tbody/tfoot).
scope
string
Для <th>: col, row, colgroup, rowgroup. Ключовий атрибут доступності.
headers
string
Список id заголовків, що відносяться до цієї комірки. Для складних таблиць з colspan/rowspan.
span
number
Атрибут <col> та <colgroup>: кількість стовпців, які охоплює ця колонка/група.

Практичні завдання


Комплексний приклад від А до Я

Тема: Розклад конференції DevUA 2024 — сторінка із програмою, спікерами та FAQ.

<!DOCTYPE html>
<html lang="uk">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta
            name="description"
            content="Програма конференції DevUA 2024: розклад доповідей, спікери, майстер-класи."
        />
        <title>Програма DevUA 2024</title>
    </head>
    <body>
        <header>
            <nav aria-label="Навігація по сторінці">
                <!-- <ul> для навігації — порядок не критичний -->
                <ul>
                    <li><a href="#schedule">Розклад</a></li>
                    <li><a href="#speakers">Спікери</a></li>
                    <li><a href="#workshops">Майстер-класи</a></li>
                    <li><a href="#faq">FAQ</a></li>
                </ul>
            </nav>
        </header>

        <main>
            <!-- ===== КЛЮЧОВІ ФАКТИ ===== -->
            <section aria-labelledby="facts-heading">
                <h2 id="facts-heading">Конференція в цифрах</h2>

                <!-- <dl> для пар параметр-значення -->
                <dl>
                    <dt>Дата</dt>
                    <dd><time datetime="2024-11-23">23–24 листопада 2024</time></dd>

                    <dt>Місце</dt>
                    <dd>UNIT.City, Київ</dd>

                    <dt>Кількість доповідей</dt>
                    <dd>42 доповіді від провідних спеціалістів</dd>

                    <dt>Треки</dt>
                    <dd>Frontend, Backend, DevOps, Architecture</dd>

                    <dt>Учасники</dt>
                    <dd>1200+ розробників</dd>

                    <dt>Мова</dt>
                    <dd>Українська, деякі доповіді — англійська</dd>
                </dl>
            </section>

            <!-- ===== РОЗКЛАД — ТАБЛИЦЯ ===== -->
            <section id="schedule" aria-labelledby="schedule-heading">
                <h2 id="schedule-heading">Розклад: День 1 (23 листопада)</h2>

                <table>
                    <caption>
                        Розклад доповідей першого дня конференції DevUA 2024. Зали: Main Stage, Frontend Track, Backend
                        Track.
                    </caption>

                    <colgroup>
                        <col />
                        <!-- Стовпець часу -->
                        <col span="3" />
                        <!-- Три зали -->
                    </colgroup>

                    <thead>
                        <tr>
                            <th scope="col">Час</th>
                            <th scope="col">Main Stage</th>
                            <th scope="col">Frontend Track</th>
                            <th scope="col">Backend Track</th>
                        </tr>
                    </thead>

                    <tbody>
                        <tr>
                            <th scope="row">09:00–09:30</th>
                            <!-- Реєстрація займає всі три зали -->
                            <td colspan="3">Реєстрація учасників та кава</td>
                        </tr>
                        <tr>
                            <th scope="row">09:30–10:15</th>
                            <!-- Відкриття — тільки Main Stage -->
                            <td colspan="3">Відкриття конференції — Вступне слово організаторів</td>
                        </tr>
                        <tr>
                            <th scope="row">10:30–11:15</th>
                            <td>State of Web 2024: куди рухається індустрія</td>
                            <td>Vue 3 Composition API: практичні патерни</td>
                            <td>PostgreSQL 17: нові можливості</td>
                        </tr>
                        <tr>
                            <th scope="row">11:30–12:15</th>
                            <td>AI у веб-розробці: реальні кейси</td>
                            <td>React Server Components у продакшні</td>
                            <td>Golang для highload: досвід Ukraine</td>
                        </tr>
                        <tr>
                            <th scope="row">12:15–13:15</th>
                            <!-- Обід займає всі зали -->
                            <td colspan="3">Обідня перерва та нетворкінг</td>
                        </tr>
                        <tr>
                            <!-- Воркшоп займає два часових слоти — rowspan="2" -->
                            <th scope="row" rowspan="2">13:15–15:30</th>
                            <td>Performance-аудит реального застосунку</td>
                            <!-- Воркшоп зайняв два слоти — rowspan -->
                            <td rowspan="2">Воркшоп: TypeScript від 0 до Pro (2 год.)</td>
                            <td rowspan="2">Воркшоп: Kubernetes для розробника (2 год.)</td>
                        </tr>
                        <tr>
                            <!-- Час вже є у попередньому рядку -->
                            <td>Web Assembly: практичний вступ</td>
                        </tr>
                        <tr>
                            <th scope="row">15:45–16:30</th>
                            <td>Micro-frontends: коли і як</td>
                            <td>CSS Container Queries: нова ера адаптивності</td>
                            <td>Event-driven architecture: від теорії до практики</td>
                        </tr>
                    </tbody>

                    <tfoot>
                        <tr>
                            <th scope="row">18:00–21:00</th>
                            <td colspan="3">After-party: нетворкінг, конкурси, DJ-сет</td>
                        </tr>
                    </tfoot>
                </table>
            </section>

            <!-- ===== СПІКЕРИ ===== -->
            <section id="speakers" aria-labelledby="speakers-heading">
                <h2 id="speakers-heading">Запрошені спікери</h2>

                <!-- <ul> — рівноцінний перелік без ієрархії -->
                <ul>
                    <li>
                        <article>
                            <h3>Олена Петренко</h3>
                            <!-- <dl> для метаданих спікера -->
                            <dl>
                                <dt>Компанія</dt>
                                <dd>Google, Staff Engineer</dd>

                                <dt>Доповідь</dt>
                                <dd>«Web Vitals 2025: метрики, що мають значення»</dd>

                                <dt>Час</dt>
                                <dd><time datetime="2024-11-23T10:30">10:30, 23 листопада</time></dd>
                            </dl>
                        </article>
                    </li>

                    <li>
                        <article>
                            <h3>Максим Ткаченко</h3>
                            <dl>
                                <dt>Компанія</dt>
                                <dd>Vercel, Engineering Manager</dd>

                                <dt>Доповідь</dt>
                                <dd>«React Server Components у продакшні: рік досвіду»</dd>

                                <dt>Час</dt>
                                <dd><time datetime="2024-11-23T11:30">11:30, 23 листопада</time></dd>
                            </dl>
                        </article>
                    </li>

                    <li>
                        <article>
                            <h3>Ірина Шевченко</h3>
                            <dl>
                                <dt>Компанія</dt>
                                <dd>Grammarly, Principal Engineer</dd>

                                <dt>Доповідь</dt>
                                <dd>«AI у веб-розробці: реальні кейси та підводні камені»</dd>

                                <dt>Час</dt>
                                <dd><time datetime="2024-11-23T11:30">11:30, 23 листопада</time></dd>
                            </dl>
                        </article>
                    </li>
                </ul>
            </section>

            <!-- ===== МАЙСТЕР-КЛАСИ ===== -->
            <section id="workshops" aria-labelledby="workshops-heading">
                <h2 id="workshops-heading">Майстер-класи</h2>

                <!-- <ol> — порядок важливий (за популярністю/рекомендацією) -->
                <ol>
                    <li>
                        <h3>TypeScript від 0 до Pro</h3>
                        <p>Ведучий: Андрій Мороз, Frontend Lead в Uklon</p>
                        <!-- Вкладений ol для програми воркшопу -->
                        <ol type="a">
                            <li>Базові типи та generics</li>
                            <li>Advanced types: утиліти та умовні типи</li>
                            <li>TypeScript у React: типізація пропсів, хуків, контексту</li>
                            <li>Налаштування TS у реальному проєкті</li>
                        </ol>
                    </li>

                    <li>
                        <h3>Kubernetes для розробника</h3>
                        <p>Ведучий: Сергій Лисенко, DevOps Engineer в EPAM</p>
                        <ol type="a">
                            <li>Основи K8s: поди, деплойменти, сервіси</li>
                            <li>Helm charts: пакетування застосунків</li>
                            <li>CI/CD пайплайни з GitHub Actions + K8s</li>
                        </ol>
                    </li>

                    <li>
                        <h3>Performance-аудит реального застосунку</h3>
                        <p>Ведуча: Наталія Ковальчук, Performance Engineer в Booking.com</p>
                        <ol type="a">
                            <li>Chrome DevTools: профілювання завантаження</li>
                            <li>Core Web Vitals: пошук та усунення проблем</li>
                            <li>Bundle analysis та оптимізація</li>
                        </ol>
                    </li>
                </ol>
            </section>

            <!-- ===== ПОРІВНЯЛЬНА ТАБЛИЦЯ КВИТКІВ ===== -->
            <section aria-labelledby="tickets-heading">
                <h2 id="tickets-heading">Квитки</h2>

                <table>
                    <caption>
                        Типи квитків DevUA 2024 та їх наповнення
                    </caption>

                    <thead>
                        <tr>
                            <th scope="col">Включено</th>
                            <th scope="col">Standard</th>
                            <th scope="col">Pro</th>
                            <th scope="col">VIP</th>
                        </tr>
                    </thead>

                    <tbody>
                        <tr>
                            <th scope="row">Доступ до всіх доповідей</th>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <th scope="row">Запис доповідей (30 днів)</th>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <th scope="row">Майстер-клас (1 на вибір)</th>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <th scope="row">VIP-зона та нетворкінг зі спікерами</th>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <th scope="row">After-party</th>
                            <td></td>
                            <td></td>
                            <td></td>
                        </tr>
                        <tr>
                            <th scope="row">Сертифікат учасника</th>
                            <td>PDF</td>
                            <td>PDF + друкований</td>
                            <td>PDF + друкований</td>
                        </tr>
                    </tbody>

                    <tfoot>
                        <tr>
                            <th scope="row">Ціна</th>
                            <td>1 500 грн</td>
                            <td>3 500 грн</td>
                            <td>7 000 грн</td>
                        </tr>
                    </tfoot>
                </table>
            </section>

            <!-- ===== FAQ — список визначень ===== -->
            <section id="faq" aria-labelledby="faq-heading">
                <h2 id="faq-heading">Часті запитання</h2>

                <dl>
                    <dt>Чи будуть записи доповідей?</dt>
                    <dd>
                        Так, записи будуть доступні впродовж 30 днів після конференції для власників квитків Pro та VIP.
                    </dd>

                    <dt>Чи є знижки для студентів?</dt>
                    <dd>
                        Так, знижка 50% для студентів денної форми навчання за наявності студентського квитка.
                        Зв'яжіться з організаторами для отримання промокоду.
                    </dd>

                    <dt>Де знаходиться UNIT.City?</dt>
                    <dd>
                        UNIT.City — інноваційний парк у Києві за адресою: вул. Дорогожицька, 3. Найближча станція метро:
                        «Дорогожичі».
                    </dd>

                    <dt>Чи можна повернути квиток?</dt>
                    <dd>
                        Повернення можливе до 7 листопада 2024 включно з утриманням 10% комісії за обробку. Після цієї
                        дати повернення не здійснюється, але можна передати квиток іншій особі.
                    </dd>

                    <dt>Яка мова доповідей?</dt>
                    <dd>
                        Більшість доповідей — українською. Окремі міжнародні спікери — англійською. Перелік мов:
                        <!-- Вкладений список всередині <dd> — це коректно -->
                        <ul>
                            <li>Українська: 36 доповідей</li>
                            <li>Англійська: 6 доповідей (без перекладу)</li>
                        </ul>
                    </dd>
                </dl>
            </section>
        </main>

        <footer>
            <nav aria-label="Посилання підвалу">
                <ul>
                    <li><a href="/privacy">Політика конфіденційності</a></li>
                    <li><a href="/terms">Умови участі</a></li>
                    <li><a href="/contacts">Контакти організаторів</a></li>
                </ul>
            </nav>
            <p><small>&copy; 2024 DevUA Conference. Всі права захищені.</small></p>
        </footer>
    </body>
</html>

Що демонструє цей приклад:

📋 Списки

<ul> для навігації, спікерів, мов — де порядок не важливий. <ol> для воркшопів та програм — де порядок має значення. Вкладені <ul> та <ol> з коректним вкладенням всередині <li>.

📑 `<dl>`

Метадані конференції, характеристики спікерів, FAQ — асоціативні пари там, де вони є найприроднішою структурою. Вкладений <ul> всередині <dd>.

📊 Таблиці

<caption>, <colgroup>, <thead>/<tbody>/<tfoot>, scope="col/row", складний colspan та rowspan у розкладі та квитках.

🏗️ Архітектура

Кожен елемент на своєму місці: <dl><table><ul>. Семантична структура з правильними <section> та aria-labelledby.

Корисні посилання

Copyright © 2026