</> Praktum

Главная / CSS / Псевдоэлементы ::before и ::after

Справочник · CSS

Псевдоэлементы ::before и ::after

Редакция PraktumОбновлено 6 мин чтенияУровень: новичок

Псевдоэлемент — часть селектора после двух двоеточий, которая стилизует часть элемента или создаёт новую. ::before и ::after добавляют виртуальный блок в начало и конец содержимого элемента — без лишних тегов в HTML. Без свойства content они не появятся.

Коротко
  • ::before вставляет блок перед содержимым элемента, ::after — после.
  • Без content псевдоэлемент не создаётся; для пустого пишут content: "".
  • Подходят для декора: иконки, кавычки, затемнение, разделители.
  • Не работают у img, input и других заменяемых элементов.
  • Два двоеточия — псевдоэлемент, одно — псевдокласс.

Минимальный пример

.external::after {
  content: " ↗";
}
.note::before {
  content: "Совет: ";
  font-weight: 700;
  color: #2a62d9;
}
<a class="external" href="https://developer.mozilla.org/">MDN</a>
<p class="note">Проверяй селектор в DevTools.</p>

У ссылки появилась стрелка после текста, у абзаца — жирное «Совет:» в начале. В HTML ничего не добавилось: эти части нарисованы стилями.

Свойство content

Что можно писать в content
ЗначениеРезультат
""пустой блок для фигур, линий, затемнений
"текст"строка; перенос — "\A" вместе с white-space: pre
attr(data-label)значение атрибута элемента
url(icon.svg)картинка
counter(step)значение CSS-счётчика
open-quote, close-quoteкавычки из свойства quotes

Если не указать content или написать content: none, псевдоэлемента не будет, и все остальные стили к нему не применятся. Это самая частая причина «::before не работает».

Псевдоэлемент — это строчный блок внутри элемента

Псевдоэлементы живут внутри элемента: ::before — первым ребёнком, ::after — последним. По умолчанию они строчные, поэтому width и height не работают, пока не задать display: block или inline-block, или не позиционировать их абсолютно.

.title::after {
  content: "";
  display: block;
  width: 48px;
  height: 3px;
  margin-top: 8px;
  background: currentColor;
}

Затемнение карточки и растянутая ссылка

.card {
  position: relative;
}
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(transparent 40%, rgb(0 0 0 / .65));
  pointer-events: none; /* клики проходят сквозь */
}

/* вся карточка кликабельна, а в HTML одна ссылка */
.card a::before {
  content: "";
  position: absolute;
  inset: 0;
}

Абсолютный псевдоэлемент с inset: 0 растягивается на всю карточку, если у неё position: relative (подробнее — в уроке position). Второй приём делает кликабельной всю карточку, хотя в HTML одна ссылка в заголовке — удобно и для скринридера, и для пальца.

Частые приёмы

/* звёздочка у обязательного поля */
.label-required::after { content: " *"; color: #c93636; }

/* подпись из data-атрибута */
.tooltip::after { content: attr(data-hint); }

/* нумерация шагов CSS-счётчиком */
.steps { counter-reset: step; }
.steps li::before {
  counter-increment: step;
  content: counter(step) ". ";
  font-weight: 700;
}

/* «ёлочки» у цитаты */
q { quotes: "«" "»"; }
q::before { content: open-quote; }
q::after  { content: close-quote; }

Псевдоэлементы хороши для повторяющегося оформления, которое не хочется копировать в HTML каждой карточки: значки, разделители, нумерация, служебные пометки.

Другие псевдоэлементы

Полезные псевдоэлементы
ПсевдоэлементЧто стилизует
::first-letterпервую букву блока — буквица
::first-lineпервую строку текста
::markerмаркер или номер пункта списка
::placeholderподсказку внутри поля ввода
::selectionвыделенный мышью текст
::backdropфон под открытым dialog
::file-selector-buttonкнопку в input type="file"
li::marker { color: #2a62d9; }
input::placeholder { color: #8a94a6; }
::selection { background: #ffe58a; }
dialog::backdrop { background: rgb(0 0 0 / .5); }

Где ::before и ::after не работают

Псевдоэлементы вставляются внутрь содержимого элемента. У заменяемых элементов — img, input, video, iframe — своего содержимого нет, поэтому img::after не отрисуется. Если нужна подпись или значок у картинки, оберни её в figure или span и вешай псевдоэлемент на обёртку. То же с полями: звёздочку обязательного поля ставят на label.

Одно или два двоеточия

По современной записи псевдоэлементы пишут с двумя двоеточиями: ::before. Старые записи с одним — :before, :after, :first-letter, :first-line — браузеры понимают ради совместимости. В новом коде пиши два двоеточия, чтобы сразу отличать псевдоэлементы от псевдоклассов вроде :hover.

Псевдоэлемент или настоящий тег

::before / ::after

Оформление без смысла: иконка, линия, затемнение, кавычки. Если стили отключить, ничего важного не пропадёт.

Настоящий элемент

Содержание: текст, цена, ссылка, кнопка. Его нужно выделить, скопировать, найти поиском — это работает только с HTML.

Частые ошибки

  • Забывают content, и псевдоэлемент не появляется.
  • Пытаются повесить ::after на img или input.
  • Задают width и height строчному псевдоэлементу без display: block или абсолютного позиционирования.
  • Кладут в content важный текст: его нельзя выделить, а поисковик может его не учесть.
  • Затемнение ::after перекрывает ссылки и кнопки — помогает pointer-events: none.

Доступность

Скринридеры обычно читают текст из content, а значки вроде «↗» или «★» могут прозвучать странно. Для декоративного текста современные браузеры поддерживают альтернативную запись content: "★" / "";: после косой черты — текст для скринридера, пустая строка скрывает значок. Важную информацию в псевдоэлементы не выноси: её нельзя выделить и скопировать, и она пропадает без CSS.

Поддержка браузерами

::before, ::after, ::first-letter, ::first-line и ::selection работают во всех браузерах. ::marker, ::placeholder, ::backdrop и ::file-selector-button поддерживаются всеми актуальными браузерами. Альтернативный текст в content ("★" / "") появился позже — проверяй на Can I use. Старый браузер пропустит непонятное ему объявление, поэтому пиши два подряд: сначала content: "★";, затем content: "★" / ""; — каждый браузер возьмёт последнее, которое понимает.

Практика

Сделай три вещи без изменения HTML: стрелку «↗» после всех внешних ссылок (у которых href начинается с http), красную звёздочку после подписи обязательного поля и нумерацию «Шаг 1, Шаг 2…» у пунктов списка с классом steps.

Показать решение
a[href^="http"]::after { content: " ↗"; }

.label-required::after { content: " *"; color: #c93636; }

.steps { counter-reset: step; list-style: none; }
.steps li::before {
  counter-increment: step;
  content: "Шаг " counter(step) ": ";
  font-weight: 700;
}

Открыть песочницу

Частые вопросы

Почему не работает ::before?

Чаще всего не задано свойство content. Без него псевдоэлемент не создаётся. Для пустого блока пиши content: "".

Чем ::before отличается от ::after?

Только местом: ::before вставляется первым ребёнком элемента, перед его содержимым, а ::after — последним, после содержимого.

Можно ли добавить ::after к картинке?

Нет. У img нет собственного содержимого, куда можно вставить псевдоэлемент. Оберни картинку в figure или span и стилизуй обёртку.

Читает ли скринридер текст из content?

Обычно да. Поэтому декоративные символы лучше скрыть записью content: "★" / "", а важный текст держать в HTML.

Писать :before или ::before?

В новом коде — ::before. Одно двоеточие браузеры понимают ради совместимости со старыми стилями.

Источники

Ещё в разделе CSS