Чем отличаются псевдоклассы от псевдоэлементов в CSS?
Вопрос
В чём разница между псевдоклассами (:hover, :nth-child) и псевдоэлементами (::before, ::after)?
Короткий ответ
Псевдокласс описывает особое состояние или позицию уже существующего элемента (наведение курсора, первый ребёнок, невалидное поле). Псевдоэлемент описывает часть элемента или генерирует новый узел, которого нет в разметке (первая строка текста, содержимое до/после элемента). По синтаксису псевдоклассы пишутся с одним двоеточием, псевдоэлементы — с двумя.
Подробный ответ
Псевдоклассы (:single-colon) выбирают элементы, которые уже есть в DOM, но находятся в определённом состоянии или позиции относительно других элементов:
- состояния взаимодействия:
:hover,:focus,:active,:visited; - состояния формы:
:checked,:disabled,:required,:valid/:invalid; - структурные/позиционные:
:first-child,:last-child,:nth-child(n),:only-child; - логические:
:not(),:is(),:where(),:has().
Псевдоэлементы (::double-colon) обращаются к части содержимого элемента, которая не имеет собственного узла в DOM, либо создают новый генерируемый узел:
::before/::after— вставляют сгенерированный контент до/после содержимого элемента; обязательно требуют свойствоcontent(даже пустоеcontent: ""), иначе не отрендерятся. Используются для декоративных элементов, иконок, кавычек, счётчиков — без засорения HTML лишними тегами.::first-line/::first-letter— стилизуют часть текстового содержимого (первую строку, первую букву), которую невозможно выделить обычным селектором.::placeholder— стилизует плейсхолдерinput.::selection— стилизует выделенный пользователем текст.
Синтаксис: по спецификации CSS3 псевдоэлементы должны писаться с двумя двоеточиями (::before), чтобы отличать их от псевдоклассов, но по историческим причинам браузеры до сих пор поддерживают одинарное двоеточие для старых псевдоэлементов (:before, :after) — в новом коде стоит явно использовать двойное.
Ключевое смысловое отличие: псевдокласс никогда не создаёт новый узел в дереве рендеринга, он лишь применяет стили к существующему элементу при определённом условии; псевдоэлемент же может фактически добавить визуальный контент, которого не было в разметке.
Пример
/* псевдокласс: состояние существующего элемента */
.button:hover {
background-color: #2563eb;
}
.list li:nth-child(odd) {
background-color: #f5f5f5;
}
input:invalid {
border-color: crimson;
}
/* псевдоэлемент: генерирует контент, которого нет в HTML */
.tooltip::before {
content: "";
position: absolute;
top: -4px;
border: 4px solid transparent;
border-bottom-color: #333;
}
.required-field::after {
content: " *";
color: crimson;
}
.article p::first-letter {
font-size: 2em;
font-weight: bold;
}
::selection {
background-color: #ffe58f;
}
Дополнительные вопросы
- Почему
::before/::afterне рендерятся без свойстваcontent? - Чем
:is()и:where()отличаются друг от друга по влиянию на specificity? - Можно ли добавить
::beforeк элементу<img>и почему это не сработает?