Главная идея
До сих пор мы выбирали элементы по тегу, классу или id — то есть по тому, что написано в HTML. Псевдоклассы и псевдоэлементы добавляют два новых измерения: выбор по текущему состоянию элемента и стилизацию частей, которых в разметке нет. Это позволяет делать интерактивный, «живой» интерфейс одним только CSS, не добавляя ни строчки JavaScript и ни одного лишнего тега.
Псевдокласс — это реакция на состояние. Представь дверь с подсветкой: пока к ней не подошли — она обычная, поднёс руку (:hover) — загорелась, открыл (:active) — мигнула. Дверь физически та же, меняется лишь её состояние, и подсветка реагирует автоматически.
Псевдоэлемент — это дорисованная деталь. Как наклейка «NEW» в углу товара на витрине: самого товара (HTML) она не часть, её приклеили поверх для красоты. ::before/::after — такие же наклейки, которые CSS «дорисовывает» в начало или конец элемента.
Один знак двоеточия или два?
Синтаксически их легко перепутать, но разница принципиальная: : — псевдокласс (состояние/позиция уже существующего элемента), :: — псевдоэлемент (новая виртуальная сущность).
::before/::after добавляются как первый и последний «ребёнок» внутри элемента — их нет в HTML, их создаёт CSS.Псевдоклассы состояния: :hover, :focus, :active
Эти три описывают, что происходит с элементом прямо сейчас: :hover — на элемент наведён курсор; :active — элемент в момент нажатия (кнопка мыши зажата); :focus — элемент получил фокус (клик по полю или переход по Tab). Правильный порядок объявления для ссылок — LVHA (:link, :visited, :hover, :active), иначе более позднее правило перебьёт более раннее.
:hover недоступен с клавиатуры и на тач-экранах. Любое интерактивное состояние дублируйте видимым :focus или :focus-visible — иначе пользователь, идущий по Tab, не поймёт, где находится.Структурные псевдоклассы: :nth-child, :first/last-child, :not, :checked
:nth-child() выбирает элемент по его номеру среди соседей: even — чётные, odd — нечётные, 3n — каждый третий. Так делают «зебру» в таблицах одним правилом. :first-child/:last-child — первый и последний в группе. :not(...) исключает: a:not(.active) — все ссылки, кроме активной. :checked срабатывает на отмеченном чекбоксе или радио — позволяет менять вид интерфейса без JavaScript.
/* зебра: подсветить каждую чётную строку */
.lesson-list li:nth-child(even) {
background: #f1f5f9;
}
/* все ссылки, кроме активной — без подчёркивания */
.lesson-list a:not(.active) {
text-decoration: none;
}
/* отмеченный чекбокс делает метку зелёной */
input:checked + label {
color: #16a34a;
}
Псевдоэлементы: ::before, ::after, ::placeholder, ::selection
::before и ::after создают виртуальный элемент в начале/конце содержимого. Они не появятся без свойства content — даже пустого (content: ''). Идеальны для декора: иконок, стрелок, разделительных линий, бейджей. ::placeholder стилизует текст-подсказку в полях ввода, ::first-line — только первую строку абзаца, а ::selection — тот фрагмент, который пользователь выделил мышью.
content в ::before/::after — декоративный. Не помещайте туда смысловой текст (его не увидят скринридеры и нельзя выделить/скопировать). Содержание — в HTML, украшения — в псевдоэлементах.Группировка: :is() и :where()
Оба сворачивают длинные перечисления селекторов: вместо h1, h2, h3 можно написать :is(h1, h2, h3). Разница — в специфичности: :is() берёт специфичность самого «сильного» аргумента, а :where() всегда имеет нулевую специфичность, поэтому его правила легко переопределить. :where() идеален для базовых стилей-«основы», которые потом будут перекрываться.
:is()/:where() и поддержку в целевых браузерах — на MDN :is() и MDN :where().Частая ошибка
Самая распространённая — написать ::before и забыть content: псевдоэлемент просто не отрисуется, и автор долго ищет «несуществующий» баг. Вторая — стилизовать только :hover, забыв :focus: на десктопе всё работает, но с клавиатуры интерфейс «слепой».