Тег li (от английского list item, «пункт списка») записывает один пункт внутри ul, ol или menu. Это парный тег, но закрывающий </li> можно опустить. Браузер выводит li как блок в режиме display: list-item: этот режим рисует слева маркер или номер, а вид маркера, его цвет и положение настраиваются в CSS.
Урок «Что можно записать внутри пункта списка» учит записывать пункты и показывает, что допустимо внутри. Здесь разберём другое: кто на самом деле задаёт маркер, как убрать точки так, чтобы они не остались у вложенных списков, и куда уходит маркер при отступах и смене display.
<ul>
<li>Чай</li>
<li>Кофе</li>
<li>Какао</li>
</ul>
В этой статье
- Тег li в HTML: что это и кто задаёт маркер пункта
- Где можно записать тег li: ul, ol, menu и ошибки с div и a
- Закрывающий тег li: когда его можно не писать
- Что можно записать внутри тега li: p, h2, a, img, table
- Тег li как ссылка: a внутри li и область нажатия
- Как убрать точки у тега li: list-style у ul и у li
- Вид маркера у li: type, list-style-type, list-style-image и ::marker
- Цвет и размер маркера li: color у li или у span
- Отступы у тега li: margin, padding и положение маркера
- Свойство display у тега li: inline, flex, float и горизонтальный список
- Тег li в JavaScript: перенести пункт между списками ul и ol
- Атрибуты тега li: value, type и глобальные
- Вопросы про тег li: первый, последний и текущий пункт
- Частые ошибки с тегом li
Тег li в HTML: что это и кто задаёт маркер пункта
Тег li блочный: он занимает всю ширину списка и начинается с новой строки. Собственных отступов у него нет: margin и padding равны нулю. Маркер рисуется не потому, что у элемента тег li, а потому, что у него display: list-item. Любому элементу, например div или p, можно задать этот режим, и он тоже получит маркер, а у li с display: block маркер пропадёт.
.punkt {
display: list-item;
margin-left: 1.5em;
}
Пример: пункт без тега li и тег li без маркера
Выберите запись: вверху её правило, под ним результат и вывод о маркерах.
Где можно записать тег li: ul, ol, menu и ошибки с div и a
Пункт li допускается только прямо внутри ul, ol и menu (последний тег описывает список команд и выводит те же круги, что ul). Браузер при этом снисходителен: li в div или внутри ссылки он выводит как обычный пункт с кругом, но валидатор считает такую запись ошибкой. Ссылку записывают внутри li, а не вокруг него.
Вид маркера задаёт не пункт, а список вокруг него: тот же li в ul получает круг, а в ol число. Нумерацию подробно разбирает страница про тег ol.
<ul>
<li>Чай</li>
</ul>
<ol>
<li>Чай</li>
</ol>
<menu>
<li>Чай</li>
</menu>
Пример: один и тот же li в разных родителях
Выберите запись: вверху её код, под результатом написано, допустима ли она и какой маркер получился.
Закрывающий тег li: когда его можно не писать
Закрывающий тег li необязателен: пункт заканчивается там, где начинается следующий li или закрывается сам список. С вложенными блоками правило не такое простое. Абзац p внутри li закрывается сам, а вот li внутри div внутри пункта не остаётся в нём: браузер закрывает div, и такой li становится соседним пунктом. Поэтому закрывающий тег лучше записывать всегда.
<ul>
<li>Чай
<li>Кофе
</ul>
Пример: какое дерево построит браузер
Выберите запись: под результатом показано дерево, которое построил браузер.
Что можно записать внутри тега li: p, h2, a, img, table
Внутри li допустимо любое содержимое потока: абзацы тега p, заголовки, ссылки тега a, картинки, таблицы, блоки div и вложенные списки. Заголовок сохраняет свой размер и поля, а маркер встаёт у его первой строки. Подсписок записывают после текста пункта и закрывают до закрывающего </li>.
<li>
<h2>Сенча</h2>
<p>Зелёный чай.</p>
</li>
Пример: что записать внутри пункта
Выберите содержимое: вверху его код, под результатом вывод. Второй пункт Кофе записан для сравнения.
Тег li как ссылка: a внутри li и область нажатия
По умолчанию ссылка занимает только ширину своего текста, а пункт шире: нажать правее текста нельзя. Чтобы нажималась вся строка, ссылке задают display: block, а чтобы цель была удобнее для пальца, добавляют padding. Пунктирная рамка вокруг ссылки в примере показывает область нажатия, а строка под примером считает её ширину.
li a {
display: block;
padding: 8px 12px;
}
Пример: область нажатия ссылки в пункте
Выберите правило: рамка показывает область нажатия, а строка под примером сравнивает её ширину с шириной пункта.
Как убрать точки у тега li: list-style у ul и у li
Маркеры убирает правило list-style: none, короткая запись для list-style-type: none. Его можно записать у списка или у пункта: свойство наследуется, поэтому правило у списка доходит до пунктов. Но у вложенных списков браузер задаёт свой вид маркера (кружок и квадрат), и унаследованное значение его не перебивает. Поэтому правило, записанное по классу внешнего списка, вложенные пункты не затрагивает: точки у них остаются.
Надёжно работают три записи: правило у самих пунктов (.menu li), правило у списка и всех вложенных (.menu, .menu ul) и сброс по тегу ul без класса. Запись .menu > li убирает точки только на первом уровне. Отступ слева после этого остаётся, как описано в разделе про как убрать точки у ul.
.menu li {
list-style: none;
}
Пример: убрать точки у вложенного списка
Выберите правило: под кодом написано, остались ли маркеры у вложенных пунктов и почему.
Вид маркера у li: type, list-style-type, list-style-image и ::marker
Вид маркера у li задаёт list-style-type (круг, квадрат, цифры), а свою картинку подставляет list-style-image. Символ вместо точки записывают в ::marker через content. Атрибут type у li тоже работает, но он устарел и действует только на тот пункт, у которого записан. Если нужен значок с собственным положением, стандартный маркер убирают и рисуют знак псевдоэлементом ::before.
li::marker {
content: '» ';
}
Пример: способы поменять маркер
Выберите способ: вверху его код, под результатом пояснение.
Цвет и размер маркера li: color у li или у span
Маркер берёт цвет и размер у самого li: color и font-size, записанные у пункта, меняют и текст, и маркер. Если цвет записан у span или a внутри пункта, маркер остаётся прежним, потому что находится вне этих элементов. Тег strong и другие вложенные теги на него тоже не влияют. Чтобы покрасить только маркер, записывают li::marker.
li::marker {
color: #FF6B6B;
}
Пример: цвет и размер маркера
Выберите правило: под результатом написано, что покрасилось.
Отступы у тега li: margin, padding и положение маркера
Отступы у li ведут себя необычно: маркер находится вне блока пункта и привязан к его внешнему краю. Поэтому margin-left сдвигает пункт вместе с маркером, а padding-left сдвигает только текст, и маркер отрывается от него. Для отступа всего списка используют padding-left у ul, а расстояние между пунктами задают через margin-bottom у li.
li {
margin-bottom: 8px;
}
Пример: отступы пункта и положение маркера
Выберите свойство и двигайте ползунок: под примером написано, что сдвинулось.
Свойство display у тега li: inline, flex, float и горизонтальный список
Маркер зависит от значения display у пункта: пока оно list-item, маркер на месте. Значения block, inline, inline-block и flex превращают пункт в обычный элемент, и маркер пропадает. А float: left оставляет пункт list-item, поэтому маркеры сохраняются, но без левого поля налезают на соседей. Горизонтальный список поэтому делают через inline-block у li или flex у ul, как в меню из раздела про ul в меню сайта.
li {
display: inline-block;
}
Пример: display у пункта и судьба маркера
Выберите значение: вверху правило, под результатом написано, остались ли маркеры.
Тег li в JavaScript: перенести пункт между списками ul и ol
Поскольку маркер зависит от списка, пункт, перенесённый скриптом из ul в ol, сразу получает номер, а из ol в ul теряет его. Метод append не копирует пункт, а перемещает его. Если нужна копия, вызывают cloneNode(true): клон попадает в новый список, а оригинал остаётся на месте.
const li = ul.firstElementChild;
ol.append(li);
Пример: перенос пункта между списками
Нажимайте кнопки: вверху выполненная команда, под списками число пунктов в каждом.
Атрибуты тега li: value, type и глобальные
Собственных атрибутов у li два. Атрибут value задаёт номер пункта в ol, а в ul и menu круг номера не показывает, хотя значение сдвигает счётчик: если у ul включить цифры, пункт получит записанный номер. Валидатор считает такую запись ошибкой. Атрибут type задаёт вид маркера одного пункта: он работает, но устарел, и валидатор выдаёт предупреждение. Остальные атрибуты в стандарте WHATWG глобальные.
| Атрибут | Статус | Что делает | Пример записи |
|---|---|---|---|
value | актуален в ol | Номер пункта, следующие продолжают счёт. В ul и menu не нужен: круг номера не показывает | <li value="7"> |
type | устарел | Вид маркера одного пункта: работает, но вместо него нужен CSS | li { list-style-type: square; } |
class, id, style, lang, title | актуален | Глобальные атрибуты: работают у любого элемента | <li class="active"> |
Вопросы про тег li: первый, последний и текущий пункт
Два вопроса, которых нет в разделах выше: как выбрать крайние и чётные пункты и как отметить текущий пункт меню.
Как выбрать первый, последний и чётные li?
Для этого есть псевдоклассы :first-child, :last-child и :nth-child(). Значение even выбирает чётные пункты, а 3n — каждый третий. Линию между пунктами рисуют селектором li + li: он выбирает все пункты, кроме первого.
li:nth-child(even) {
background: #FFF1EA;
}
Пример: первый, последний и чётные пункты
Выберите селектор: под результатом перечислены выделенные пункты.
Как выделить текущий пункт меню: li.active или aria-current?
Есть два способа. Класс на li только красит пункт. Атрибут aria-current="page" на ссылке не только даёт стиль через селектор a[aria-current="page"], но и сообщает программам, какая страница текущая. Оба способа не отличаются на экране, поэтому выбирают атрибут: он работает и как стиль, и как смысл.
<li>
<a href="/uroki" aria-current="page">Уроки</a>
</li>
Пример: текущий пункт меню
Выберите способ и пункт: вверху код, под меню строка с названием выделенного пункта.
Частые ошибки с тегом li
Типичные ошибки с тегом li и как их исправить.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
li вне ul, ol и menu | Браузер выводит с кругом, валидатор считает ошибкой | Записать пункт внутри списка |
a вокруг li внутри ul | Ошибка валидатора: ссылка не допустима прямо в списке | Записать ссылку внутри li |
value у li в ul | Круг номера не показывает, валидатор считает ошибкой | Использовать value только в ol |
type у li | Работает, но устарел и действует на один пункт | Задать list-style-type в CSS |
.menu { list-style: none } и точки у вложенных | У вложенных списков маркеры остаются | Записать .menu li или .menu, .menu ul |
inline-block или flex у li и ожидание маркера | Маркер пропадает вместе с режимом list-item | Вернуть list-item или нарисовать знак через ::before |
color у span внутри li ради маркера | Маркер остаётся прежним | Записать li::marker |
padding-left у li вместо отступа списка | Текст уехал, маркер остался на месте | Задать отступ у ul или использовать margin-left |
li внутри div внутри пункта без закрывающих тегов | Браузер закрывает div, пункт становится соседним | Записывать закрывающие теги и вкладывать li только в список |
Ссылка в пункте без display: block | Нажимается только ширина текста | Задать ссылке display: block и padding |
float: left у li для строки меню | Маркеры налезают на соседние пункты | Использовать inline-block у li или flex у ul |