Олег Марков
ARIA label в HTML - подробное руководство по доступным интерфейсам
Введение
ARIA-label в HTML — это атрибут, который помогает сделать элементы интерфейса понятными для технологий доступности: скринридеров, браузеров со специальными режимами, голосовых помощников. С его помощью вы можете задать текстовое описание элементу, у которого либо нет собственного текста, либо этот текст не отражает его реальную функцию.
Смотрите, здесь важно понять одну идею: визуально пользователи могут видеть иконку "лупы" и догадаться, что это поиск, но скринридер без правильной подписи просто озвучит "кнопка" или прочитает имя файла иконки. ARIA-label решает эту проблему — он добавляет скрытое текстовое описание, которое слышит пользователь скринридера, но не видит обычный пользователь.
В этой статье я покажу вам:
- что такое ARIA-label и как он работает;
- чем он отличается от других ARIA-атрибутов;
- когда его использовать, а когда нет;
- как правильно писать тексты для ARIA-label;
- типичные ошибки и проблемы, с которыми часто сталкиваются разработчики.
Давайте по шагам разберемся, как использовать ARIA-label так, чтобы интерфейс стал действительно доступным, а не просто "с отметкой галочки" в чек-листе.
Что такое ARIA и где здесь ARIA-label
Кратко про WAI-ARIA
WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) — это набор атрибутов, которые расширяют семантику HTML. Они помогают браузеру и ассистивным технологиям понять:
- что это за элемент (роль — role);
- в каком он состоянии (атрибуты вроде aria-checked, aria-expanded);
- как его правильно озвучить (атрибуты вроде aria-label, aria-labelledby, aria-describedby).
Важно: ARIA не заменяет обычную HTML-семантику, а дополняет ее. Если можно использовать нативный тег, его нужно использовать в первую очередь: button, a, label, input, nav и т. д.
Что именно делает ARIA-label
ARIA-label — это атрибут, который задает элементу текстовую метку, невидимую на экране, но доступную для скринридеров. Проще говоря, это "скрычная подпись", которая:
- не отображается визуально;
- не занимает место в макете;
- не зависит от внутреннего текста элемента;
- полностью заменяет собой текстовую метку для ассистивных технологий.
Покажу вам минимальный пример:
<button aria-label="Открыть главное меню">
<!-- Иконка бургера, без текста -->
<svg aria-hidden="true" focusable="false">
<!-- ... -->
</svg>
</button>// aria-label добавляет текст "Открыть главное меню" для скринридера
// визуально пользователь видит только иконку
Скринридер озвучит это как "Открыть главное меню, кнопка". Именно это и нужно от такого элемента.
Когда нужно использовать ARIA-label
Основные случаи применения
ARIA-label нужен не везде. Его логично использовать в следующих ситуациях:
Элемент не имеет видимого текста:
- иконки в кнопках (лупа, корзина, "гамбургер");
- круглые кнопки без подписи;
- иконки управления: play, pause, close.
Видимый текст есть, но он не описывает действие:
- "Подробнее" рядом с несколькими товарами;
- "Открыть" рядом с документами;
- несколько одинаковых кнопок "Редактировать" в таблице.
Нужно уточнить контекст действия:
- "Удалить пользователя Иван";
- "Открыть профиль компании".
Давайте разберемся на примере с кнопкой-иконкой поиска.
<button type="submit" aria-label="Найти по сайту">
<svg aria-hidden="true" focusable="false">
<!-- Иконка лупы -->
</svg>
</button>// type="submit" - это кнопка отправки формы
// aria-label - "Найти по сайту" - текст для скринридера
// svg скрыт от скринридера через aria-hidden
Здесь скринридер озвучит "Найти по сайту, кнопка", хотя на экране пользователь видит только иконку.
Когда ARIA-label лучше не использовать
ARIA-label — не универсальная палочка-выручалочка. Есть случаи, когда его применять не стоит:
У элемента уже есть подходящий видимый текст:
Например:<button>Сохранить</button>// Здесь кнопка уже имеет текст "Сохранить"
// Добавлять aria-label="Сохранить" не нужноЕсли вы добавите aria-label с таким же текстом, вы не получите пользы, зато увеличите риск рассинхронизации: текст на кнопке изменят, а aria-label забудут.
Вместо ARIA-label лучше использовать aria-labelledby:
Если у вас уже есть видимый текст в другом месте (например, label для input), то правильнее "привязать" этот текст через aria-labelledby, а не дублировать его в aria-label. Об этом чуть позже разберем отдельно.Нельзя "переписать" смысл нативных элементов:
Например, не стоит использовать aria-label для того, чтобы "маскировать" неправильный элемент, вроде:<div role="button" aria-label="Сохранить"> Ссылка </div>// Это антипример
// Здесь нужно использовать вместоЛучше исправить семантику, чем пытаться ее скрыть.
Как работает ARIA-label "внутри" ассистивных технологий
Как скринридеры используют ARIA-label
Когда скринридер встречает элемент, он формирует "озвучиваемую строку" из нескольких частей:
- роль элемента (кнопка, ссылка, поле ввода);
- имя (label) — это как раз aria-label, aria-labelledby или видимый текст;
- состояние (отмечено, отключено, раскрыто и т. д.).
Если у элемента есть aria-label, то:
- этот текст обычно имеет приоритет над видимым текстом;
- скринридер воспринимает его как "имя" элемента;
- внутренний текст элемента может игнорироваться (зависит от реализации).
Посмотрим на примере:
<button aria-label="Оформить заказ">
Купить
</button>// Визуально пользователь видит "Купить"
// Скринридер озвучит "Оформить заказ, кнопка"
Можно сказать, что aria-label "перекрывает" собой видимый текст как имя элемента для скринридера. Поэтому важно не создавать логический конфликт между тем, что пользователь видит, и тем, что слышит.
Приоритет ARIA-имени
У элемента может быть несколько источников "имени". Условный порядок приоритета часто такой:
- aria-labelledby
- aria-label
- встроенный/видимый текст или связанный label
Это значит:
- если есть aria-labelledby — он главный;
- если его нет, но есть aria-label — берется он;
- если нет и его, берется текстовое содержимое или связанный label.
Поэтому если вы используете aria-label и aria-labelledby одновременно, многие скринридеры будут использовать aria-labelledby, а aria-label игнорировать. Так что сочетать их почти никогда не нужно.
Различия между aria-label, aria-labelledby и aria-describedby
aria-label vs aria-labelledby
Оба атрибута задают "имя" (label) элемента, но делают это по-разному.
- aria-label — вы прямо пишете текст в атрибуте.
- aria-labelledby — вы ссылаетесь на id другого элемента, текст которого используется как метка.
Давайте посмотрим на сравнение.
Пример с aria-label
<input
type="text"
aria-label="Поиск по сайту"
/>// Визуальной подписи нет
// Для скринридера поле озвучится как "Поиск по сайту, поле ввода"
Пример с aria-labelledby
<label id="search-label" for="search-input">
Поиск по сайту
</label>
<input
id="search-input"
type="text"
aria-labelledby="search-label"
/>// Текст "Поиск по сайту" виден пользователю
// aria-labelledby "привязывает" этот текст как метку к полю
Если говорить проще:
- aria-label — текст внутри кода, невидимый;
- aria-labelledby — ссылка на уже существующий видимый текст.
Когда есть видимый заголовок или подпись, гораздо лучше использовать aria-labelledby вместо aria-label: так вы избегаете дублирования текста в коде и повышаете согласованность интерфейса.
Когда выбирать aria-label, а когда aria-labelledby
Можно сформулировать практическое правило:
- Есть видимый текст, который логично использовать как метку — берите aria-labelledby.
- Видимого текста нет или он не подходит — используйте aria-label.
Покажу пример с карточкой товара, где подпись находится в соседнем элементе.
<h3 id="product-title-42">Ноутбук Pro 15</h3>
<button aria-labelledby="product-title-42">
<!-- Иконка корзины -->
<svg aria-hidden="true" focusable="false">
<!-- ... -->
</svg>
</button>// Кнопка визуально содержит только иконку
// aria-labelledby указывает на заголовок товара
// Скринридер может озвучить: "Ноутбук Pro 15, кнопка"
А теперь тот же пример с aria-label:
<button aria-label="Добавить ноутбук Pro 15 в корзину">
<svg aria-hidden="true" focusable="false">
<!-- ... -->
</svg>
</button>// Текст полностью находится в aria-label
// Это удобно, если нужно описать действие более явно
Здесь выбор зависит от ваших задач: если важнее сохранить динамическую связь с реальным названием товара, aria-labelledby лучше. Если важно именно действие ("добавить в корзину"), можно использовать aria-label.
aria-label vs aria-describedby
aria-describedby — это не имя элемента, а дополнительное описание. Оно не заменяет основную метку, а добавляет контекст. Например:
- подсказка по формату ввода;
- предупреждение;
- дополнительное пояснение.
Смотрите, я покажу пример:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-describedby="email-help"
/>
<p id="email-help">
Используйте рабочий email - мы отправим на него подтверждение.
</p>// "Email" - основная метка для поля (label)
// aria-describedby добавляет описание "Используйте рабочий email..."
// Скринридер читает сначала метку, затем описание
Важный момент: aria-label и aria-describedby решают разные задачи и могут использоваться вместе. aria-label задает краткое "имя", aria-describedby расширяет его дополнительными деталями.
Типичные сценарии использования ARIA-label
Кнопка-иконка без текста
Один из самых частых случаев — кнопка в интерфейсе, которая содержит только иконку.
<button type="button" aria-label="Закрыть диалог">
<svg aria-hidden="true" focusable="false">
<!-- Иконка крестика -->
</svg>
</button>// Визуально - только крестик
// aria-label - "Закрыть диалог" объясняет действие
// svg скрыт от скринридера, чтобы он не мешал восприятию
Обратите внимание:
- aria-hidden="true" на svg — чтобы скринридер не пытался "озвучить" саму иконку;
- focusable="false" — для некоторых браузеров, чтобы SVG не попадал в таб-индексацию.
Несколько одинаковых действий в списке
Представьте таблицу пользователей, где у каждой строки есть кнопка "Редактировать".
<tr>
<td id="user-ivan">Иван Петров</td>
<td>
<button aria-label="Редактировать пользователя Иван Петров">
Редактировать
</button>
</td>
</tr>// Визуально в каждой строке будет просто "Редактировать"
// Для скринридера добавлен контекст "пользователя Иван Петров"
Здесь aria-label помогает отличать одинаковые по тексту кнопки в разных строках.
Иногда удобнее привязаться к уже существующему тексту через aria-labelledby:
<tr>
<td id="user-ivan">Иван Петров</td>
<td>
<button aria-labelledby="user-ivan edit-label-ivan"></button>
<span id="edit-label-ivan" class="visually-hidden">
Редактировать
</span>
</td>
</tr>// aria-labelledby может ссылаться на несколько id
// Имена объединяются скринридером в одну фразу
// span с классом visually-hidden виден скринридеру, но не виден визуально
Класс visually-hidden — это распространенный паттерн для скрытого текста. Он добавляется через CSS, чтобы текст не был виден, но оставался доступным для ассистивных технологий.
Сложные компоненты: выпадающие меню, переключатели
ARIA-label часто используется в компонентах, где элемент визуально представлен иконкой или стилизован необычно.
Посмотрим на пример кнопки, которая открывает боковое меню:
<button
type="button"
aria-label="Открыть навигационное меню"
aria-expanded="false"
aria-controls="main-nav"
>
<svg aria-hidden="true" focusable="false">
<!-- Иконка бургера -->
</svg>
</button>
<nav id="main-nav" hidden>
<!-- Ссылки меню -->
</nav>// aria-label - текст метки для кнопки
// aria-expanded - состояние раскрытия меню (меняется JS)
// aria-controls - связь с элементом навигации
При нажатии по кнопке вы в JavaScript:
- меняете aria-expanded с false на true;
- показываете или скрываете nav.
ARIA-label здесь описывает действие или назначение кнопки, а aria-expanded сообщает текущее состояние.
Поля ввода без видимой подписи
Иногда по дизайну поля ввода не имеют видимой подписи, особенно в поиске, фильтрах или компактных формах. Но для скринридера это проблема — без метки поле теряет смысл.
Здесь aria-label — рабочее решение:
<form>
<input
type="search"
name="q"
aria-label="Поиск по каталогу"
/>
</form>// Визуально поле без подписи
// aria-label дает скринридеру текст "Поиск по каталогу"
Но если есть возможность добавить видимый label — это обычно лучшее решение:
<label for="search-field" class="visually-hidden">
Поиск по каталогу
</label>
<input
id="search-field"
type="search"
name="q"
/>// Для зрячих пользователей метка скрыта стилями
// Для ассистивных технологий она существует как обычный label
Как писать хорошие тексты для ARIA-label
Основные правила
ARIA-label — это не просто любой текст. Чтобы интерфейс был понятен, стоит придерживаться нескольких принципов:
Точность и ясность
Описывайте действие или назначение конкретно.Плохо:
- "Кнопка"
- "Иконка"
Лучше:
- "Открыть корзину"
- "Закрыть окно"
Избегайте "лишних слов"
Не нужно включать в aria-label слово "кнопка", "ссылка" и т. п. Скринридер сам озвучит роль элемента.Плохо:
- "Кнопка закрыть окно"
Лучше:
- "Закрыть окно"
Синхронизируйте с визуальным интерфейсом
Текст, который слышит пользователь, не должен противоречить тому, что он видит на экране. Если кнопка визуально подписана "Удалить", aria-label не должен говорить "Сохранить".Учитывайте контекст
В списках, таблицах и карточках иногда нужно включать часть контекста в aria-label: название товара, имя пользователя, номер заказа и т. д.Пример:
- "Удалить пользователя Иван Петров"
- "Открыть заказ 12345"
Паттерны именования
Давайте посмотрим на несколько распространенных паттернов, которые вы можете использовать.
Действие + объект
- "Открыть меню"
- "Закрыть уведомление"
- "Добавить товар в корзину"
<button aria-label="Удалить товар из корзины">
<svg aria-hidden="true" focusable="false">
<!-- Иконка корзины со значком удаления -->
</svg>
</button>// aria-label явно описывает, что произойдет при нажатии
Состояние + действие
Иногда полезно объединить в метке и текущий статус, и действие. Хотя часть состояния можно вынести в aria-атрибуты (aria-pressed, aria-expanded), текст иногда можно слегка уточнить.
Но лучше не зашивать состояние в aria-label, а использовать для этого aria-атрибуты. Например:
<button
type="button"
aria-label="Закрепить сообщение"
aria-pressed="false"
>
<!-- Иконка булавки -->
</button>// aria-label - "Закрепить сообщение"
// aria-pressed - указывает, закреплено ли сообщение сейчас
Чего лучше избегать
Длинных и перегруженных фраз.
ARIA-label — это краткая метка, а не подробное описание. Для больших текстов лучше использовать aria-describedby.Дублирования текста, уже видимого в интерфейсе, если смысл не меняется.
Например, на кнопке "Сохранить" нет смысла писать aria-label="Сохранить".Неоднозначных фраз без контекста:
В таблице с десятками строк метка "Редактировать" без уточнений делает навигацию по клавиатуре намного сложнее.
Практические примеры с пояснениями
Пример 1: Иконка закрытия модального окна
Давайте разберемся на простом диалоге:
<div
role="dialog"
aria-labelledby="dialog-title"
aria-modal="true"
>
<h2 id="dialog-title">Настройки профиля</h2>
<button
type="button"
aria-label="Закрыть настройки профиля"
>
<svg aria-hidden="true" focusable="false">
<!-- Иконка крестика -->
</svg>
</button>
<!-- Содержимое диалога -->
</div>// role="dialog" - объявляем диалоговое окно
// aria-labelledby - связывает заголовок с диалогом
// aria-modal="true" - диалог модальный
// на кнопке - aria-label "Закрыть настройки профиля"
Здесь aria-label уточняет, что именно закрывается, а не просто "Закрыть". Пользователь скринридера слышит более понятное описание.
Пример 2: Карусель изображений
Представим слайдер с кнопками "вперед" и "назад" без текстовых подписей:
<div class="carousel" aria-roledescription="карусель">
<button
type="button"
class="carousel-prev"
aria-label="Предыдущее изображение"
>
<svg aria-hidden="true" focusable="false">
<!-- Стрелка влево -->
</svg>
</button>
<div class="carousel-track">
<!-- Слайды -->
</div>
<button
type="button"
class="carousel-next"
aria-label="Следующее изображение"
>
<svg aria-hidden="true" focusable="false">
<!-- Стрелка вправо -->
</svg>
</button>
</div>// Кнопки имеют только иконки
// aria-label сообщает направление навигации
// aria-roledescription может уточнять тип компонента (необязательно)
Пользователь клавиатуры и скринридера сможет понять, что это за элементы и как ими управлять.
Пример 3: Иконки социальных сетей
Классический футер с соц.сетями:
<ul class="social-links">
<li>
<a
href="https://t.me/example"
aria-label="Открыть Telegram компании"
>
<svg aria-hidden="true" focusable="false">
<!-- Иконка Telegram -->
</svg>
</a>
</li>
<li>
<a
href="https://github.com/example"
aria-label="Открыть GitHub проекта"
>
<svg aria-hidden="true" focusable="false">
<!-- Иконка GitHub -->
</svg>
</a>
</li>
</ul>// Визуально есть только иконки соцсетей
// aria-label поясняет, куда ведет каждая ссылка
Здесь aria-label делает навигацию предсказуемой и понятной без зрительного восприятия.
Типичные ошибки при использовании ARIA-label
Переписывание видимого текста
Распространенная ошибка — устанавливать aria-label с текстом, отличным от видимого, без реальной потребности.
<button aria-label="Оформить">Купить</button>// Пользователь видит "Купить"
// Пользователь скринридера слышит "Оформить"
// Это создает путаницу, если они обсуждают интерфейс вместе
Исправление — синхронизировать оба текста:
- либо изменить видимый текст;
- либо убрать aria-label, если он ничего не добавляет.
Использование ARIA-label вместо label у полей ввода
Иногда разработчики вообще убирают тег label и заменяют его на aria-label:
<input type="text" aria-label="Имя" />// Работать будет, но это не лучший подход
Проблема в том, что:
- видимая подпись полезна всем пользователям;
- клик по label может фокусировать поле ввода;
- ищущие системы и вспомогательные инструменты часто ориентируются на явные label.
Лучшее решение — использовать настоящий label, а aria-label — только там, где метка не может быть видимой.
<label for="name-input">Имя</label>
<input id="name-input" type="text" />// Здесь aria-label уже не нужен - у поля есть явная метка
Избыточное дублирование текста
Еще одна ошибка — дублировать один и тот же текст и в label, и в aria-label, и в placeholder.
<label for="email">Email</label>
<input
id="email"
type="email"
aria-label="Email"
placeholder="Email"
/>// aria-label здесь ничего нового не добавляет
// Placeholder не заменяет подпись, но может дублировать ее
Здесь aria-label лишний и может стать источником ошибок в будущем, если тексты разойдутся.
Использование ARIA-label для "маскировки" плохой семантики
Иногда пытаются "задним числом" сделать доступным элемент, который изначально сделан неправильно.
<div onclick="submitForm()" aria-label="Отправить форму">
Отправить
</div>// Визуально это выглядит как кнопка
// Но это div, который не получает фокус с клавиатуры
// Нажать его с клавиатуры нельзя без дополнительных обработчиков
Такой подход не решает проблему доступности. Лучше переписать элемент как:
<button type="submit">Отправить</button>// Нативная кнопка изначально доступна
// Здесь даже не нужен aria-label
ARIA не предназначен для того, чтобы "спрятать" неверную разметку. Он дополняет, а не заменяет ее.
Лучшие практики использования ARIA-label
1. Сначала — нативные HTML элементы
Перед тем как тянуться к ARIA-label, задайте себе вопрос: можно ли решить задачу нативными средствами?
- использовать button вместо div;
- использовать label вместо aria-label там, где метка может быть видимой;
- использовать alt у img, если это контентное изображение.
ARIA-label — это следующий шаг, когда обычных средств недостаточно.
2. Минимум ARIA, только там, где он действительно нужен
Перегружать элементы ARIA-атрибутами без необходимости не стоит. Это усложняет код и может запутать ассистивные технологии.
Хороший ориентир: если элемент и так полностью понятен и озвучивается корректно — не добавляйте aria-label "на всякий случай".
3. Следите за актуальностью текстов
ARIA-label содержит строки, которые могут устареть:
- поменялся текст в дизайне;
- изменился сценарий использования;
- поменялись названия сущностей.
Хорошая практика — держать тексты для aria-label рядом с другими текстами интерфейса (например, в системе локализации), а не "зашивать" их в нескольких местах верстки.
4. Тестируйте реальным скринридером
Самый надежный способ проверить правильность использования ARIA-label — пройтись по интерфейсу со скринридером:
- NVDA или JAWS в Windows;
- VoiceOver в macOS и iOS;
- TalkBack в Android.
Пройдите по странице с клавиатуры и послушайте, как озвучиваются элементы с aria-label. Сразу будут видны:
- слишком общие метки;
- противоречия с видимым текстом;
- избыточные или дублирующие описания.
5. Избегайте вложенных интерактивных элементов
ARIA-label иногда пытаются "нацепить" на контейнер, внутри которого уже есть кнопки, ссылки или поля. Важно помнить: интерактивные элементы не должны быть вложены друг в друга.
Плохой пример:
<button aria-label="Открыть меню">
<a href="#">Меню</a>
</button>// И кнопка, и ссылка интерактивны
// aria-label на внешнем элементе не решает эту проблему
Лучше разделить роли и назначать aria-label только нужному элементу.
Заключение
ARIA-label — это точечный инструмент для улучшения доступности интерфейса, который:
- добавляет элементу текстовую метку, невидимую визуально;
- помогает скринридерам корректно озвучивать кнопки, ссылки и поля без текста;
- особенно полезен при использовании иконок, компактных интерфейсов и динамических компонентов.
Однако эффективное использование ARIA-label требует аккуратности:
- он не заменяет нативные элементы HTML и теги label;
- его не стоит применять там, где уже есть понятный видимый текст;
- тексты в aria-label должны быть точными, краткими и согласованными с интерфейсом.
Хороший подход — использовать ARIA-label только там, где вам действительно нужно добавить или уточнить имя элемента для ассистивных технологий, а во всех остальных случаях опираться на правильную семантическую разметку и видимые метки.
Частозадаваемые технические вопросы
Как сделать разные aria-label для одной и той же кнопки в зависимости от состояния
Используйте JavaScript и атрибуты состояния. Например, для кнопки "показать/скрыть пароль":
<button
type="button"
id="toggle-password"
aria-label="Показать пароль"
aria-pressed="false"
>
<!-- Иконка глаза -->
</button>
<script>
// Здесь мы меняем aria-label и aria-pressed при клике
document.getElementById('toggle-password').addEventListener('click', function () {
const isPressed = this.getAttribute('aria-pressed') === 'true';
this.setAttribute('aria-pressed', String(!isPressed));
this.setAttribute(
'aria-label',
isPressed ? 'Показать пароль' : 'Скрыть пароль'
);
});
</script>Можно ли использовать и aria-label, и title вместе
Можно, но нужно понимать разницу:
- aria-label — для ассистивных технологий;
- title — показывает системную подсказку при наведении мыши.
Если вы используете оба, убедитесь, что тексты согласованы и не противоречат друг другу. Для чисто доступных меток часто достаточно aria-label без title.
Как локализовать aria-label при мультиязычном интерфейсе
Относитесь к aria-label как к обычным строкам интерфейса. Храните их:
- в файлах локализации;
- в JSON со строками переводов;
- в шаблонах с поддержкой i18n.
Важный момент — не "зашивайте" текст aria-label жестко в верстке, если остальная часть интерфейса уже локализуется через отдельные словари.
Почему aria-label не читается скринридером на моем элементе
Проверьте несколько моментов:
- Элемент не скрыт (display none, visibility hidden или aria-hidden="true").
- Элемент реально попадает в фокус клавиатуры (tabindex или нативная интерактивность).
- На этом же элементе нет aria-labelledby, которое может иметь больший приоритет.
- Вы тестируете актуальную разметку в реальном скринридере, а не только в DevTools.
Как добавить aria-label к кастомной кнопке на div без потери доступности
Если вы по каким-то причинам используете div как кнопку, вам нужно:
- добавить role="button";
- сделать элемент фокусируемым (tabindex="0");
- обрабатывать как click, так и клавиши Enter/Space;
- добавить aria-label, если нет видимого текста.
<div
role="button"
tabindex="0"
aria-label="Открыть фильтры"
onclick="openFilters()"
onkeydown="if (event.key === 'Enter' || event.key === ' ') openFilters()"
>
<!-- Иконка фильтров -->
</div>// Но по возможности лучше заменить div на нативный
Постройте личный план изучения Html до уровня Middle — бесплатно!
Html — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Html
Лучшие курсы по теме

HTML и CSS
Антон Ларичев
TypeScript с нуля
Антон Ларичев