CSS: псевдоклассы и псевдоэлементы
Введение: интерфейс, который реагирует на пользователя
Представьте входную дверь с разными состояниями: закрыта, открывается, заблокирована.
С кнопками, ссылками и полями в интерфейсе та же логика: у каждого элемента есть состояние и визуальная реакция.
С кнопками, ссылками и полями в интерфейсе та же логика: у каждого элемента есть состояние и визуальная реакция.
Псевдоклассы и псевдоэлементы в CSS как раз отвечают за такие моменты.
Они помогают сделать интерфейс понятным, доступным и аккуратным без лишней разметки.
Они помогают сделать интерфейс понятным, доступным и аккуратным без лишней разметки.
💡 Совет:
Всегда проектируйте
hover вместе с focus-visible, а не отдельно.✅ Вывод:
Псевдоклассы и псевдоэлементы превращают «статичную верстку» в живой UI.
Проблема -> решение
Проблема:
Без состояний элементы выглядят одинаково: пользователь не понимает, что уже нажато, что доступно, где ошибка формы и где сейчас фокус.
Решение:
Использовать псевдоклассы для состояния (
:hover, :focus-visible, :checked) и псевдоэлементы для декоративных частей (::before, ::after, ::marker).✅ Вывод:
Состояния и псевдоэлементы снимают большую часть базовых UX-проблем в интерфейсе.
Чем помогает и как работает
Псевдоклассы и псевдоэлементы помогают:
- дать пользователю обратную связь при наведении, фокусе и клике;
- подсветить ошибки и текущий статус формы;
- добавить декоративные детали без лишних
spanи дополнительного HTML; - сделать код чище за счет селекторов состояния и структуры.
Как это работает:
- Шаг 1: определяете, какие состояния важны для элемента (наведение, фокус, выбран, отключен).
- Шаг 2: задаете базовый стиль элемента без состояния.
- Шаг 3: добавляете псевдоклассы для интерактивных и структурных сценариев.
- Шаг 4: добавляете псевдоэлементы там, где нужна декоративная часть (иконка, бейдж, маркер).
- Шаг 5: проверяете доступность: виден ли фокус, не теряется ли смысл без декора.
- Шаг 6: тестируете реальные сценарии: клавиатура, длинные тексты, disabled-состояния.
✅ Вывод:
Логика простая: состояние описываем псевдоклассом, визуальную добавку - псевдоэлементом.
Ключевые термины (простыми словами)
- Pseudo-class (псевдокласс) - стиль элемента в конкретном состоянии.
- Pseudo-element (псевдоэлемент) - виртуальная часть элемента, которой нет в HTML.
- State (состояние) - текущий контекст элемента: наведён, в фокусе, выбран.
- Selector specificity (специфичность) - приоритет селектора в конфликте стилей.
- Focus ring (контур фокуса) - видимая подсветка элемента при навигации клавиатурой.
- Structural selector (структурный селектор) - выбор элемента по позиции среди соседей.
1. Псевдокласс и псевдоэлемент: базовая разница
Назначение:
Понимать, когда вы описываете состояние элемента, а когда добавляете его декоративную часть.
Простыми словами:
Псевдокласс = «как элемент себя ведет», псевдоэлемент = «что у элемента визуально добавилось».
Для новичка:
Если вы видите один двоеточие
:, это чаще про состояние. Если двойное ::, это виртуальная часть элемента.Аналогия:
Псевдокласс - настроение человека, псевдоэлемент - его аксессуар.
Пример:
a:hover { color: #2563eb;} .tag::before { content: "•"; margin-right: 6px;}🔎 Как это происходит на практике:
- В карточке курса ссылка меняет цвет при наведении.
- Перед названием курса добавляют точку-маркер через
::before. - HTML остается чистым, поведение и декор живут в CSS.
Характеристики:
- ✅
:обычно для состояния; - ✅
::обычно для визуальной части; - ✅ в реальных проектах используются вместе.
Когда использовать:
Всегда, когда нужна обратная связь или декоративная деталь без усложнения HTML.
✅ Вывод:
Главный вопрос: это состояние элемента или отдельная визуальная часть?
2. Интерактивные состояния: :hover, :focus-visible, :active
Назначение:
Показывать пользователю, что элемент доступен, выбран или нажат.
Простыми словами:
Интерфейс должен отвечать на действие человека: навел, перешел клавишей Tab, нажал.
Для новичка:
hover - мышь, focus-visible - клавиатура, active - момент нажатия.Аналогия:
Кнопка как физический выключатель: вы видите подсветку, фокус и клик.
Пример:
.btn:hover { background: #2563eb; color: #fff;} .btn:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px;} .btn:active { transform: translateY(1px);}🔎 Как это происходит на практике:
- Дизайнер задает интерактивные состояния кнопки.
- Разработчик реализует
hoverиactive. - QA проверяет клавиатуру: при Tab фокус виден и не пропадает.
Характеристики:
- ✅
hoverне заменяетfocus-visible; - ✅
activeкороткий, но важный для тактильности; - ✅ без фокуса страдает доступность.
Когда использовать:
Для всех интерактивных элементов: ссылки, кнопки, пункты меню, вкладки.
✅ Вывод:
Качественный UI всегда учитывает мышь и клавиатуру одновременно.
3. Состояния форм: :checked, :disabled, :invalid, :required
Назначение:
Показывать статус ввода и доступность действий в форме.
Простыми словами:
Форма должна сразу сообщать: «выбрано», «нельзя нажать», «ошибка», «обязательное поле».
Для новичка:
Когда человек заполняет форму, он должен видеть состояние без догадок.
Аналогия:
Это как чек-лист с пометками: галочка, ошибка, блокировка.
Пример:
input:required { border-color: #d1d5db;} input:invalid { border-color: #ef4444;} input:checked + span { color: #16a34a;} button:disabled { opacity: 0.5; cursor: not-allowed;}🔎 Как это происходит на практике:
- В форме подписки email невалиден - поле краснеет.
- Пока чекбокс согласия не отмечен, кнопка отправки отключена.
- После отметки чекбокса текст рядом подсвечивается.
Характеристики:
- ✅ быстрое визуальное подтверждение;
- ✅ меньше ошибок при вводе;
- ✅ понятные состояния без JS для базовых кейсов.
Когда использовать:
В любых формах: регистрация, фильтры, анкеты, настройки.
✅ Вывод:
Псевдоклассы форм напрямую влияют на конверсию и удобство.
4. Структурные псевдоклассы: :first-child, :last-child, :nth-child()
Назначение:
Стилизовать элементы по их позиции внутри контейнера.
Простыми словами:
Можно выбрать первый, последний, каждый второй или любой по формуле.
Для новичка:
Это способ быстро сделать «зебру» в списке и не проставлять классы вручную.
Аналогия:
Нумерация мест в поезде: можно оформить четные и нечетные по-разному.
Пример:
.card:first-child { border-color: #2563eb;} .card:last-child { margin-bottom: 0;} .card:nth-child(even) { background: #f9fafb;}🔎 Как это происходит на практике:
- В каталоге карточек нужна визуальная ритмика.
- Дизайнер просит выделить каждый второй элемент.
- Разработчик добавляет
:nth-child(even)без изменения HTML.
Характеристики:
- ✅ меньше служебных классов;
- ✅ быстрые локальные правки;
- ✅ удобно для табличных и карточных списков.
Когда использовать:
Когда стиль зависит от позиции элемента внутри списка.
✅ Вывод:
Позиционные селекторы экономят время, если использовать их осознанно.
5. Логические псевдоклассы: :is(), :not(), :has()
Назначение:
Сокращать сложные селекторы и описывать условия точнее.
Простыми словами:
Можно объединить несколько вариантов, исключить класс или выбрать родителя по состоянию потомка.
Для новичка:
is = «любой из», not = «кроме», has = «содержит внутри».Аналогия:
Фильтр в магазине: включить нужные категории, исключить лишние, оставить товары с нужным признаком.
Пример:
.card:is(.is-new, .is-hot) { border-color: #2563eb;} .btn:not(.is-disabled) { cursor: pointer;} .form:has(input:invalid) { border-color: #ef4444;}🔎 Как это происходит на практике:
- В компоненте много модификаторов, селекторы начинают дублироваться.
- Команда использует
:is()для группировки. - Через
:has()родитель формы подсвечивается, если внутри есть ошибка.
Характеристики:
- ✅ CSS становится короче;
- ✅ условия читаются яснее;
- ✅ легче сопровождать большой UI.
Когда использовать:
В компонентах со сложными состояниями и несколькими вариациями.
✅ Вывод:
Логические псевдоклассы уменьшают дублирование и повышают читаемость CSS.
6. Контекстные состояния: :focus-within, :target, :empty
Назначение:
Стилизовать блок в зависимости от контекста взаимодействия и содержания.
Простыми словами:
Можно подсветить весь контейнер, когда фокус внутри, выделить раздел по якорю и обработать пустой блок.
Для новичка:
Это «умные» селекторы: смотрят не только на сам элемент, но и на его окружение.
Аналогия:
Подсветка комнаты, когда в ней кто-то есть, или указатель на главу, куда вы перешли по ссылке.
Пример:
.field-group:focus-within { border-color: #2563eb;} section:target { outline: 2px solid #93c5fd;} .note:empty { display: none;}🔎 Как это происходит на практике:
- Форма выглядит как единый блок, который подсвечивается при фокусе в любом поле.
- В FAQ якорная ссылка ведет к вопросу и подсвечивает его.
- Пустой блок подсказки автоматически скрывается.
Характеристики:
- ✅ лучше навигация и ориентирование;
- ✅ меньше JS для простых реакций;
- ✅ чище поведение компонентов.
Когда использовать:
В формах, длинных документах, FAQ, карточках с опциональным контентом.
✅ Вывод:
Контекстные псевдоклассы делают интерфейс более предсказуемым и умным.
7. Декоративные псевдоэлементы: ::before и ::after
Назначение:
Добавлять визуальные детали без изменения HTML-разметки.
Простыми словами:
Это «добавочные слои» вокруг контента: иконка, бейдж, линия, фон-акцент.
Для новичка:
Помните правило: без
content псевдоэлемент не появится.Аналогия:
Наклейка на папке: меняет вид, но не меняет документы внутри.
Пример:
.badge::before { content: "NEW"; margin-right: 8px; color: #2563eb; font-weight: 700;} .quote::after { content: ""; display: block; margin-top: 8px; height: 2px; background: #e5e7eb;}🔎 Как это происходит на практике:
- В каталоге нужно пометить новые курсы без правок шаблона HTML.
- Через
::beforeдобавляют бейдж. - Через
::afterделают декоративную линию под цитатой.
Характеристики:
- ✅ минимум изменений в разметке;
- ✅ удобно для UI-декора;
- ✅ легко включать и отключать темами.
Когда использовать:
Для декоративных элементов, которые не несут критический смысл.
✅ Вывод:
::before и ::after ускоряют визуальные правки и сохраняют HTML чистым.8. Псевдоэлементы текста и списков: ::placeholder, ::selection, ::marker
Назначение:
Точно стилизовать части текста, выделения и маркеры списка.
Простыми словами:
Можно сделать подсказку мягче, выделение текста фирменным, маркеры списка заметнее.
Для новичка:
Эти селекторы улучшают восприятие деталей, которые пользователь видит постоянно.
Аналогия:
Это как тонкая настройка шрифта, подсветки и пунктов в печатной инструкции.
Пример:
input::placeholder { color: #9ca3af;} ::selection { background: #fde68a; color: #111827;} li::marker { color: #2563eb;}🔎 Как это происходит на практике:
- В поле поиска placeholder делают менее контрастным, чтобы не путать с введенным текстом.
- В статье на платформе брендируют цвет выделения текста.
- В списке преимуществ через
::markerусиливают визуальную иерархию.
Характеристики:
- ✅ аккуратная типографика и UI-детали;
- ✅ улучшение читаемости;
- ✅ единый визуальный стиль.
Когда использовать:
В формах, контентных страницах, документации и списках преимуществ.
✅ Вывод:
Мелкие псевдоэлементы часто заметно повышают качество интерфейса.
Must-know факты (часто спрашивают и часто путают)
:focus-visibleне то же самое, что:focus: он лучше для доступного UX.:hoverне должен быть единственной обратной связью.::beforeи::afterтребуютcontent, иначе не рендерятся.- Псевдоэлементы не подходят для критически важного текста.
:nth-child()считает всех детей,:nth-of-type()- только выбранный тип.:visitedограничен браузером по соображениям безопасности.:has()полезен, когда нужно стилить родителя по состоянию дочернего элемента.- Контур фокуса нельзя убирать без равноценной замены.
✅ Вывод:
Если помнить эти правила, большинство типичных ошибок с псевдоклассами не возникнет.
Сравнение подходов
| Что сравниваем | Когда подходит | Плюсы | Риск при неверном применении |
|---|---|---|---|
Псевдокласс (:hover, :focus) | Нужна реакция на состояние | Понятный интерактив | Потеря доступности без focus-visible |
Псевдоэлемент (::before, ::after) | Нужен декор без HTML | Чистая разметка | Попытка положить в декор важный смысл |
Структурные (:nth-child) | Стиль зависит от позиции | Меньше лишних классов | Хрупкость при изменении DOM |
Логические (:is, :not, :has) | Сложные условия селектора | Меньше дублирования | Переусложнение без читаемости |
Часто спрашивают на собеседованиях
- В чем точная разница между псевдоклассом и псевдоэлементом?
- Почему
:focus-visibleпредпочтительнее:focusдля UI? - Когда использовать
:nth-child, а когда:nth-of-type? - Какие ограничения есть у
:visitedи почему? - В каких кейсах
:has()реально полезен в production? - Почему важный текст нельзя переносить в
::beforeи::after? - Что чаще всего ломают при работе с
hoverна мобильных?
✅ Вывод:
На собеседовании проверяют не знание списка селекторов, а понимание UX-последствий и ограничений.
Типичные ошибки
Ошибка 1: Есть hover, но нет видимого фокуса
❌ Неправильно:
Добавлять состояние только для мыши.
✅ Правильно:
Писать
:focus-visible рядом с :hover.Почему:
Клавиатурная навигация без видимого фокуса становится почти непригодной.
Ошибка 2: Забыли content у ::before и ::after
❌ Неправильно:
Стилизовать псевдоэлемент без
content.✅ Правильно:
Всегда задавать
content (хотя бы пустую строку).Почему:
Без
content псевдоэлемент не появляется.Ошибка 3: Важный текст вынесен в псевдоэлемент
❌ Неправильно:
Ключевой смысл страницы добавлять через
::before.✅ Правильно:
Смысловой контент хранить в HTML, а псевдоэлемент использовать только для декора.
Почему:
Декоративный слой не должен заменять реальный контент.
Ошибка 4: Путают :nth-child() и :nth-of-type()
❌ Неправильно:
Использовать
:nth-child() там, где в контейнере смешанные теги.✅ Правильно:
Выбирать селектор по реальной структуре DOM.
Почему:
nth-child считает всех детей, и стили могут попадать не туда.Ошибка 5: Удаляют outline без замены
❌ Неправильно:
outline: none; без альтернативной подсветки.✅ Правильно:
Давать кастомный контур через
:focus-visible.Почему:
Иначе пользователь теряет ориентир по клавиатуре.
Ошибка 6: Слишком сложные селекторы с :is/:has
❌ Неправильно:
Писать «умные» селекторы, которые никто не может поддерживать.
✅ Правильно:
Держать правила читаемыми и использовать логические псевдоклассы точечно.
Почему:
CSS должен быть поддерживаемым для всей команды.
Best Practices
- Держите набор интерактивных состояний как стандарт дизайн-системы.
- Всегда проверяйте сценарии мыши, клавиатуры и touch.
- Используйте псевдоэлементы для декора, не для смысла.
- Для форм заранее проектируйте
:invalid,:disabled,:checked. - Перед релизом прогоняйте визуальный чек фокуса и доступности.
- Если селектор сложно читать, упростите его или используйте класс.
Заключение
Псевдоклассы и псевдоэлементы - это основа «живого» CSS, который объясняет пользователю, что происходит в интерфейсе.
Когда состояния и декор оформлены правильно, UI становится понятным, доступным и легче поддерживается командой.
Когда состояния и декор оформлены правильно, UI становится понятным, доступным и легче поддерживается командой.
Ключевые мысли
- Псевдокласс отвечает за состояние, псевдоэлемент - за визуальную часть.
focus-visibleи доступность нельзя считать опциональными.- Чем чище логика селекторов, тем легче поддержка проекта.