Олег Марков
Элемент списка HTML li - как правильно создавать и оформлять элементы списка
Введение
Элемент списка li — один из самых частых «рабочих» тегов в HTML. Вы используете его каждый раз, когда создаете меню, список преимуществ, чек-лист, таблицу содержимого или нумерованный план. Но за кажущейся простотой скрывается много нюансов: семантика, вложенность, управление нумерацией, стилизация, доступность, поведение при использовании с CSS и JavaScript.
Здесь я шаг за шагом покажу вам, как работать с li осознанно: не просто «чтобы работало», а с учетом стандартов, удобства сопровождения и доступности для всех пользователей.
Что такое li и где он используется
Основное назначение элемента li
Элемент li (list item) — это тег, который обозначает отдельный пункт списка. Его ключевая особенность в том, что он:
- всегда должен находиться внутри контейнерного списка;
- описывает одну логическую единицу внутри этой группы;
- по умолчанию не может существовать сам по себе без родительского списка.
Основная семантика элемента li — это «элемент набора схожих элементов». В HTML такими наборами обычно являются:
- ul — маркированный список (unordered list);
- ol — нумерованный список (ordered list);
- menu — меню (редко используется, но формально допустимо в HTML).
Давайте сразу посмотрим на простой пример.
<ul>
<li>Элемент списка номер один</li>
<li>Элемент списка номер два</li>
<li>Элемент списка номер три</li>
</ul>// ul — контейнер для маркированного списка
// каждый li — отдельный пункт внутри списка
Как видите, li не используется без контейнера. Если попробовать разместить li напрямую в body, валидатор HTML укажет на ошибку структуры документа.
Обязательное окружение для li
По стандарту HTML элемент li допускается внутри следующих элементов:
- ul — наиболее распространенный случай;
- ol — используется для упорядоченных списков с нумерацией;
- menu — логическое меню (в реальных проектах встречается редко и чаще заменяется на ul).
Пример с ol:
<ol>
<li>Зарегистрироваться на сайте</li>
<li>Подтвердить электронную почту</li>
<li>Заполнить профиль</li>
</ol>// ol — нумерованный список
// браузер автоматически добавляет нумерацию 1 2 3 к элементам li
Если вы случайно завернете li, например, в div без ul или ol, HTML скорее всего «починит» разметку на лету, но итоговая структура может отличаться от ожидаемой. Поэтому лучше следить за правильным контекстом сразу.
Основные типы списков с li
Маркированный список ul + li
Маркированный список используется там, где порядок элементов не важен. Например, список характеристик, список преимуществ, перечень пунктов меню.
<ul>
<li>Быстрая доставка</li>
<li>Поддержка 24/7</li>
<li>Гарантия возврата в течение 30 дней</li>
</ul>// ul — каждый пункт отмечается маркером (точкой или другим символом)
// порядок элементов здесь не несет смысловой нагрузки
Браузер по умолчанию применяет к li в ul маркер в виде точки, но тип маркера можно легко поменять с помощью CSS. Чуть позже мы посмотрим, как это сделать.
Нумерованный список ol + li
Нумерованный список используют, когда порядок элементов важен: инструкции, шаги, рейтинги, этапы процессов.
<ol>
<li>Выберите тариф</li>
<li>Введите данные карты</li>
<li>Подтвердите оплату</li>
</ol>// ol — браузер автоматически создает нумерацию
// логический порядок 1 2 3 важен для понимания инструкции
С ol связан еще один важный момент — управление нумерацией с помощью атрибутов start и value. Мы разберем это отдельно.
Список-меню menu + li
Элемент menu используется редко, однако по спецификации он также может содержать элементы li. На практике почти всегда для меню используют ul, так как это более предсказуемо и принято в сообществе разработчиков.
<nav>
<ul>
<li><a href="/">Главная</a></li>
<li><a href="/blog">Блог</a></li>
<li><a href="/contacts">Контакты</a></li>
</ul>
</nav>// в навигации принято использовать ul а не menu
// каждый li — отдельный пункт меню со ссылкой
Структура и содержимое li
Что можно помещать внутрь li
Внутри элемента li можно размещать практически любой контент:
- текст;
- ссылки;
- изображения;
- другие списки (вложенные списки);
- блоки div, article, section и похожие элементы;
- формы или их части.
Вот пример сложного элемента списка. Смотрите, я покажу вам, как это работает.
<ul>
<li>
<h3>Тариф Базовый</h3>
<p>Подходит для личного использования и небольших проектов.</p>
<ul>
<li>До 3 проектов</li>
<li>До 5 пользователей</li>
<li>Поддержка по email</li>
</ul>
</li>
</ul>// внутри li есть заголовок абзац и вложенный ul
// это один логический пункт — описание конкретного тарифа
Важно помнить: li — блочный элемент по умолчанию. То есть он занимает всю ширину контейнера и располагается друг под другом. Это удобно, когда нужно управлять отступами и оформлением через CSS.
Вложенные списки и уровни структуры
Вложенные списки удобны, когда вам нужно показать иерархию: основной пункт и его подэлементы. Теперь вы увидите, как это выглядит в коде.
<ul>
<li>Фрукты
<ul>
<li>Яблоки</li>
<li>Груши</li>
<li>Бананы</li>
</ul>
</li>
<li>Овощи
<ul>
<li>Помидоры</li>
<li>Огурцы</li>
</ul>
</li>
</ul>// вложенный ul внутри li создает подсписок
// так передается иерархия категорий и элементов
Обратите внимание, что вложенный список также должен быть обернут в ul или ol, а не просто набором дополнительных li.
Атрибуты li и управление нумерацией
Атрибут value в li внутри ol
Для нумерованных списков вы можете управлять номером конкретного пункта с помощью атрибута value. Это полезно, когда нужно:
- продолжить нумерацию после пропуска;
- начать список не с единицы;
- создать разорванный список с осознанной нумерацией.
Давайте разберемся на примере.
<ol>
<li>Первый шаг</li>
<li>Второй шаг</li>
<li value="10">Сразу десятый шаг</li>
<li>Следующий шаг будет одиннадцатым</li>
</ol>// третий li имеет атрибут value="10"
// нумерация будет 1 2 10 11 — браузер продолжит от установленного значения
Атрибут value работает только внутри нумерованных списков ol. В ul он игнорируется.
Атрибут start у ol и взаимодействие с li
Иногда нужно задать стартовое значение для всего списка. Для этого у ol есть атрибут start. Он задает номер первого элемента списка.
<ol start="5">
<li>Пятый пункт</li>
<li>Шестой пункт</li>
<li>Седьмой пункт</li>
</ol>// нумерация начинается с 5
// значения для li рассчитываются автоматически — 5 6 7
Если одновременно использовать start у ol и value у конкретного li, приоритет будет у value для этого элемента.
Атрибут type для ol и стиль нумерации
Хотя атрибут type официально считается устаревшим для ol, в практике он все еще встречается. Он влияет на вид нумерации:
- 1 — стандартные арабские цифры (по умолчанию);
- A — заглавные латинские буквы;
- a — строчные латинские буквы;
- I — римские цифры заглавные;
- i — римские цифры строчные.
Пример:
<ol type="A">
<li>Пункт A</li>
<li>Пункт B</li>
<li>Пункт C</li>
</ol>// нумерация будет A B C
// часто используется в юридических документах или сложных списках
На новых проектах лучше управлять внешним видом нумерации через CSS (list-style-type), но понимание type поможет при разборе старого кода.
Стилизация li с помощью CSS
Управление маркерами: list-style-type
Стилизация li почти всегда идет в связке с родительским ul или ol. Один из самых частых сценариев — изменить вид маркера или убрать его.
<ul class="features">
<li>Легкий старт</li>
<li>Простое управление</li>
<li>Гибкие настройки</li>
</ul>.features {
list-style-type: square; /* меняем маркеры на квадраты */
}// свойство list-style-type применяется к ul
// автоматически меняется отображение маркеров у всех вложенных li
Несколько распространенных значений list-style-type:
- disc — стандартная закрашенная точка;
- circle — незакрашенный кружок;
- square — квадрат;
- decimal — числа (обычно для ol);
- none — маркеры отключены.
Пример отключения маркеров:
ul.menu {
list-style-type: none; /* убираем стандартные маркеры */
padding-left: 0; /* убираем отступ слева */
}// часто используется для навигационных меню
// дальше можно стилизовать li как горизонтальное меню
Расположение и отступы у li
Браузеры по умолчанию задают отступы для ul и ol. В реальной верстке почти всегда эти отступы настраивают вручную.
ul,
ol {
margin: 0; /* сбрасываем внешние отступы */
padding-left: 1.5rem; /* задаем контролируемый левый отступ */
}
li {
margin-bottom: 0.5rem; /* расстояние между пунктами */
}// такой подход дает предсказуемые отступы
// удобно для единообразного оформления во всем проекте
Горизонтальное расположение пунктов списка
Очень часто li используют для меню, где пункты нужно выстроить в одну строку. Покажу вам, как это реализовано на практике.
<ul class="nav">
<li><a href="/">Главная</a></li>
<li><a href="/services">Услуги</a></li>
<li><a href="/about">О компании</a></li>
</ul>.nav {
list-style: none; /* убираем маркеры */
padding-left: 0; /* убираем отступ слева */
display: flex; /* выстраиваем элементы в линию */
gap: 1.5rem; /* расстояние между пунктами меню */
}
.nav li {
/* можно добавить дополнительные стили при необходимости */
}// flex делает li строчными блоками
// gap удобно задает равномерное расстояние
Раньше для этого часто использовали inline-block или float, но сейчас flex — более простой и предсказуемый вариант.
Пользовательские маркеры с псевдоэлементами
Если стандартные маркеры вас не устраивают, можно отключить их и добавить свои с помощью ::before. Давайте посмотрим, что происходит в следующем примере.
<ul class="checklist">
<li>Регистрация выполнена</li>
<li>Профиль заполнен</li>
<li>Подписка активирована</li>
</ul>.checklist {
list-style: none; /* отключаем стандартный маркер */
padding-left: 0;
}
.checklist li {
position: relative; /* для позиционирования псевдоэлемента */
padding-left: 24px; /* место под кастомный маркер */
}
.checklist li::before {
content: "✔"; /* кастомный символ маркера */
position: absolute;
left: 0;
top: 0;
color: green;
}// создаем собственный маркер с помощью псевдоэлемента ::before
// li получает отступ чтобы текст не налезал на маркер
Этот прием часто используют в маркетинговых блоках, списках преимуществ, чек-листах.
Доступность и семантика списков с li
Почему важно использовать li правильно
Экранные читалки и другие ассистивные технологии сильно зависят от семантики. Когда вы используете ul/ol + li, пользователь:
- слышит, что начался список;
- получает количество пунктов в списке;
- может перемещаться по пунктам списка с помощью специальных клавиш.
Если вместо li вы просто выведите текст с иконками, для пользователей с читателями экрана это будет просто набор несвязанных абзацев.
Пример корректной разметки:
<h2>Что входит в тариф</h2>
<ul>
<li>Неограниченное количество проектов</li>
<li>Ежедневный бэкап</li>
<li>Поддержка по телефону и email</li>
</ul>// здесь у пользователя есть понятное объявление списка
// и ясная структура — заголовок плюс набор элементов
Когда список — действительно список
Иногда разработчики используют ul/li для выравнивания элементов, которые по смыслу не являются списком. Например, иконки соцсетей, оформленные как список, — еще допустимый вариант, так как это все-таки набор однородных элементов.
Но вот сетка карточек товаров как ul + li — спорный с точки зрения семантики вариант. Если вы представляете «набор товаров», а не «список характеристик», чаще уместнее использовать div и более семантические элементы (article, section).
Подход такой: если вы при описании говорите «список чего-то» — используйте ul/ol + li, если «сетка/набор карточек» — думайте, нужна ли здесь именно семантика списка.
Работа с li в JavaScript
Получение списка элементов li
Очень часто вам нужно программно обойти элементы списка: посчитать количество, применить обработчики событий, добавить или убрать пункты. Здесь я размещаю пример, чтобы вам было проще понять.
<ul id="todo">
<li>Купить продукты</li>
<li>Оплатить счета</li>
<li>Позвонить клиенту</li>
</ul>// Получаем список элементов li внутри списка с id="todo"
const items = document.querySelectorAll("#todo li");
// Выводим текст каждого пункта в консоль
items.forEach((item, index) => {
console.log(index, item.textContent);
// index — порядковый номер в NodeList
// item.textContent — текст содержимого элемента li
});// querySelectorAll возвращает статический список элементов li
// можно итерироваться по нему с помощью forEach
Динамическое добавление элементов li
Теперь давайте перейдем к следующему шагу — добавим новый элемент списка через JavaScript.
// Находим ul по id
const list = document.getElementById("todo");
// Создаем новый элемент li
const newItem = document.createElement("li");
newItem.textContent = "Запланировать встречу"; // задаем текст
// Добавляем новый li в конец списка
list.appendChild(newItem);// createElement создает новый DOM-узел li
// appendChild вставляет его в конец списка
При этом браузер автоматически обновит отображение: для ol — нумерацию, для ul — маркеры.
Удаление элемента li
Удалить элемент списка также несложно. Обратите внимание, как этот фрагмент кода решает задачу.
// Удаляем первый элемент списка
const firstItem = list.querySelector("li"); // находим первый li
if (firstItem) {
list.removeChild(firstItem); // удаляем его из ul
}// сначала находим li в DOM
// затем через removeChild удаляем из родителя
В современных браузерах можно использовать и более короткий способ:
firstItem?.remove(); // если элемент существует — удалить его// оператор ?. предотвращает ошибку если элемента нет
Типичные ошибки при работе с li
Использование li вне списка
Иногда разработчики по ошибке создают li напрямую внутри div или другого контейнера, без ul/ol. Визуально браузер может попытаться «исправить» ситуацию, но:
- валидность HTML нарушается;
- поведение может отличаться между браузерами;
- ассистивные технологии могут некорректно озвучивать структуру.
Правильный вариант: всегда оборачивать элементы li в ul/ol.
Неправильно:
<div>
<li>Пункт 1</li>
<li>Пункт 2</li>
</div>Правильно:
<div>
<ul>
<li>Пункт 1</li>
<li>Пункт 2</li>
</ul>
</div>Разрыв списка лишними обертками
Другая распространенная ошибка — размещать блоки, которые нарушают непрерывность списка. Например:
<ol>
<li>Пункт 1</li>
</ol>
<div>Какой-то блок между</div>
<ol start="2">
<li>Пункт 2</li>
</ol>С точки зрения браузера это два разных списка, хотя визуально можно добиться иллюзии одного списка. Если вам нужен один логический список, лучше использовать один ol и управлять оформлением через CSS, а не разрывать структуру.
Лишние отступы и «двойные» маркеры
Иногда пытаются стилизовать li так, что получается «двойной» маркер: стандартный браузерный плюс добавленный псевдоэлемент. Чтобы такого не происходило, при создании кастомных маркеров всегда отключайте стандартные:
.custom-list {
list-style: none; /* отключили базовый маркер */
padding-left: 0; /* убрали базовый отступ */
}// это базовый шаг перед созданием своих маркеров через ::before
// иначе браузер добавит и стандартный и ваш собственный маркер
Практические шаблоны использования li
Навигационное меню
Самый частый сценарий — горизонтальное или вертикальное меню. Покажу вам один из базовых шаблонов.
<nav class="main-nav">
<ul>
<li><a href="/">Главная</a></li>
<li><a href="/products">Продукты</a></li>
<li><a href="/pricing">Цены</a></li>
<li><a href="/contacts">Контакты</a></li>
</ul>
</nav>.main-nav ul {
list-style: none; /* без маркеров */
margin: 0;
padding-left: 0;
display: flex; /* горизонтальное меню */
gap: 1rem;
}
.main-nav a {
text-decoration: none; /* убрали подчеркивание */
color: #222;
padding: 0.5rem 1rem;
}
.main-nav a:hover {
background-color: #f0f0f0; /* подсветка при наведении */
}// li служит контейнером для ссылки
// flex делает меню гибким и удобным для адаптивной верстки
Список шагов процесса
Еще один сценарий — пошаговые инструкции. Здесь li удобно комбинировать с CSS-счетчиками, но можно обойтись базовой нумерацией.
<ol class="steps">
<li>Заполните анкету</li>
<li>Дождитесь звонка менеджера</li>
<li>Подпишите договор</li>
<li>Получите доступ к сервису</li>
</ol>.steps {
max-width: 480px;
}
.steps li {
margin-bottom: 0.75rem;
}// ol автоматически нумерует шаги
// li обеспечивает читаемую поэтапную структуру
Список свойств или характеристик
Иногда нужно показать пары «название — значение». Здесь можно использовать список для единообразия.
<ul class="product-specs">
<li><strong>Мощность</strong> 1200 Вт</li>
<li><strong>Вес</strong> 3.5 кг</li>
<li><strong>Гарантия</strong> 2 года</li>
</ul>.product-specs {
list-style: none; /* убираем маркеры */
padding-left: 0;
}
.product-specs li {
margin-bottom: 0.25rem;
}// каждый li — одна характеристика
// strong подсвечивает название свойства
Заключение
Элемент li — базовый кирпичик любой структурированной информации в HTML. При правильном использовании он:
- задает четкую, понятную иерархию данных;
- улучшает доступность для пользователей с ассистивными технологиями;
- облегчает стилизацию и управление содержимым через CSS и JavaScript.
Ключевые моменты, на которые стоит опираться в работе:
- li всегда используется внутри ul, ol или menu;
- для нумерованных списков вы можете управлять номерами через start у ol и value у li;
- внешний вид маркеров и отступы лучше настраивать через CSS;
- для сложных пунктов списка можно использовать любые вложенные элементы, включая другие списки;
- не забывайте про семантику и доступность — список должен оставаться списком по смыслу, а не только по внешнему виду.
Если вы будете помнить об этих принципах, работа с li станет предсказуемой и удобной, а разметка — понятной как для людей, так и для браузеров и машинных инструментов.
Частозадаваемые технические вопросы
Как убрать маркеры только у вложенного списка li а не у всего списка
Если вам нужно убрать маркеры только у второго уровня списка, а первый оставить, используйте селекторы дочерних ul:
ul ul {
list-style: none; /* убираем маркер у вложенных ul */
padding-left: 1rem; /* оставляем небольшой отступ для структуры */
}// селектор ul ul выбирает только списки внутри других ul
// основной список при этом сохраняет маркеры
Как сделать нумерацию продолженной если список разбит на несколько ol
Формально это разные списки, но можно имитировать непрерывную нумерацию через атрибут start:
<ol>
<li>Пункт 1</li>
<li>Пункт 2</li>
</ol>
<ol start="3">
<li>Пункт 3</li>
<li>Пункт 4</li>
</ol>// первый список заканчивается на 2
// второй начинается с 3 за счет атрибута start
Как задать индивидуальный номер только некоторым li в середине ol
Используйте атрибут value на нужных пунктах:
<ol>
<li>Пункт 1</li>
<li>Пункт 2</li>
<li value="10">Пункт 10</li>
<li>Пункт 11</li>
</ol>// третий li получает номер 10
// четвертый автоматически становится 11 без дополнительных настроек
Как сделать разные маркеры для разных уровней вложенности списка
Настройте list-style-type для разных уровней через селекторы:
ul {
list-style-type: disc; /* первый уровень — точки */
}
ul ul {
list-style-type: circle; /* второй уровень — кружки */
}
ul ul ul {
list-style-type: square; /* третий уровень — квадраты */
}// каждый уровень вложенности получает свой тип маркера
// так визуально подчеркивается иерархия
Как превратить li в кликабельную область целиком а не только текст ссылки
Оборачивайте содержимое li в a и делайте ссылку блочным элементом:
<ul class="cards">
<li>
<a href="/product/1">
<h3>Товар 1</h3>
<p>Краткое описание</p>
</a>
</li>
</ul>.cards a {
display: block; /* ссылка занимает всю площадь li */
padding: 1rem;
}// теперь клик по любой точке внутри li сработает как клик по ссылке
// это улучшает удобство использования на мобильных устройствах
Постройте личный план изучения Html до уровня Middle — бесплатно!
Html — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Html
Лучшие курсы по теме

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