Привет, Хабр! Меня зовут Максим Васянович, я спикер курса “Веб-верстка” в Skillbox. Сегодня поговорим о верстке, а точнее - о нюансах работы с псевдоэлементами before и after. Статья будет полезна, прежде всего, начинающим верстальщикам. Но, возможно, и профи будет интересно освежить эти моменты в памяти. 

Псевдоэлементы - мощный инструмент для создания дополнительной стилизации элементов. В этой статье посмотрим, для чего их можно использовать и как.

Что такое псевдоэлементы и зачем они нужны

Это дополнения к элементам, которые создаются с помощью CSS. Они не размещаются в разметке, но, если заглянуть в DevTools, их можно найти в разделе Elements. 

Использовать псевдоэлементы можно для самых разных целей. Описать все - не хватит и объема небольшой книги, не то что статьи. Так что в этом материале я хочу рассмотреть два полезных псевдоэлемента - ::before  и ::after

По умолчанию, псевдоэлементы ::before и ::after делают то, что должны - добавляют нечто до элемента и после элемента. Однако, на практике почти никто не использует эту возможность, т.к. потребность в ней возникает крайне редко. Ниже я расскажу о десяти способах реального использования данных псевдоэлементов в работе.

  1. Иконки для элементов

С помощью псевдоэлементов можно сделать иконки для элементов. Например, для ссылки с телефоном нужно добавить иконку-трубку. Вот простой пример использования этой возможности.

<a href="tel:+79999999999">+7 (999) 999-9999</a>

.link {

  display: inline-flex;

  align-items: center;

  text-decoration: none;

}

.link--phone::before {

  content: "";

  display: inline-block;

  margin-right: 10px;

  width: 1em;

  height: 1em;

  background-image: url("https://cdn-icons-png.flaticon.com/512/597/597177.png");

  background-position: center;

  background-size: cover;

  background-repeat: no-repeat;

}

Тут все просто: указываем размеры, дисплей, отступ, а также саму иконку - с помощью background. И самое важное - это свойство content. Да, здесь оно со значением пустой строки (и будет таким почти во всех примерах), однако без него псевдоэлементы вообще не появятся.

У предложенного решения два плюса: мы вынесли иконку в CSS, чем разгрузили разметку, а также создали отдельный класс .link--phone, который всегда будет добавлять эту иконку, если надо.

Поиграть с этим кодом можно по ссылке

2.Счетчики на элементах

Нередко в дизайне сайтов встречается набор элементов, которые имеют порядковый номер: 01, 02, 03, 04 и т.п. Представьте, что количество таких элементов каждый день растет, объем контента сайта увеличивается, и с каждым новым блоком вам придется вручную писать каждую цифру. Это крайне неудобно, так что для это цели придумали счетчики, которые реализуются как раз с помощью псевдоэлементов. Давайте разберем на примере:

<div class="parent">

  <div class="block"></div>

  <div class="block"></div>

  <div class="block"></div>

</div>

.parent {

  width: 1000px;

  margin: 0 auto;

  display: flex;

  flex-wrap: wrap;

  gap: 30px;

  counter-reset: numbers

}

.block {

  position: relative;

  min-height: 300px;

  width: 30%;

  border: 1px solid #000;

}

.block::after {

  position: absolute;

  right: 10px;

  bottom: 10px;

  counter-increment: numbers;

  content: counter(numbers);

}

Здесь нас интересует несколько вещей. Во-первых, для родителя итерируемых элементов (в нашем случае div с классом parent) мы задаем свойство counter-reset. Это, по сути, имя нашего счетчика, который мы далее будем использовать. Можно сюда написать что угодно по смыслу, в нашем случае будет numbers.

Далее, у самих элементов нужно создать псевдоэлемент (before или after  - неважно, т.к. мы используем абсолютное позиционирование), и указать в нем два свойства:

  1. counter-increment: numbers - здесь мы указываем, что значение будет инкриментировано (будет увеличиваться), и название будет то же, что и у counter-reset

  2. content: counter(numbers) - а здесь запускаем счетчик с помощью CSS-функции counter. Теперь это число будет увеличиваться в зависимости от количества блоков.

Если ваше число должно отличаться особым образом, например не “1, 2, 3”, а “01, 02, 03”, вы можете модернизировать свойство content, напрямую добавив в него число 0. Например: content: “0” counter(numbers).

Вы можете поиграть с примером по ссылке.

3.Кастомные чекбоксы и радиокнопки

Как известно, стилизация чекбоксов и радиокнопок - дело непростое. Напрямую стилизовать их нельзя, так что приходится использовать обходные пути. Один из таких путей - использование псевдоэлемента. Посмотрим на пример:

<label class="checkbox">

  <input type="checkbox" class="checkbox__input">

  <span class="checkbox__text">Фильтр</span>

</label>

.checkbox {

  user-select: none;

  position: relative;

  cursor: pointer;

}

.checkbox__text {

  padding-left: calc(1em + 10px);

}

.checkbox__input {

  -webkit-appearance: none;

    appearance: none;

}

.checkbox__input::before {

    content: '';

    cursor: pointer;

    position: absolute;

  top: -2px;

  left: 0;

  width: 1em;

  height: 1em;

  border: 3px solid crimson;

  border-radius: 100%;

}

.checkbox__input:checked::before {

    background: crimson;

}

Самое важное - стили инпута и его псевдоэлемента. Сперва мы задаем инпуту appearance: none, внешне скрывая стандартный чекбокс. Затем с помощью псевдоэлемента рисуем простой кружок с бордером. И только когда чекбокс в состоянии checked (то есть нажат, активен), применяем дополнительный стиль, задаем фон кружочку. 

Вы можете поиграть с примером по ссылке

4.Обводка с градиентом

Сделать градиент через свойство border крайне трудно, а в некоторых браузерах просто невозможно. Но и здесь можно обойти систему, использовав псевдоэлементы. Посмотрим пример:

<div class="image">

  <img src="https://www.xaprb.com/media/2018/08/kitten.jpg" alt="Спящий кот">

</div>

.image {

  position: relative;

  padding: 5px;

  width: 400px;

}

img {

  max-width: 100%;

}

.image::before {

  content: "";

  position: absolute;

  top: 0;

  left: 0;

  bottom: 0;

  right: 0;

  background-image: linear-gradient(crimson, yellow);

  z-index: -1;

}

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

Вы можете поиграть с примером по ссылке

5.Кастомные иконки у списка

Через псевдоэлемент можно делать и кастомные иконки для списков. Вы можете использовать даже эмоджи, если это требуется.

<ul class="list">

  <li>Элемент 1</li>

  <li>Элемент 2</li>

  <li>Элемент 3</li>

  <li>Элемент 4</li>

</ul>

.list {

    list-style: none;

}

.list li::before {

    content: "????";

    margin-right: 15px;

    font-size: 20px;

}

Здесь сбрасываются стандартные точки с помощью list-style, а затем с помощью псевдоэлемента добавляется кастомная иконка. Эмоджи вставлен не фоном, как делали ранее, а прямо в свойство content.

Вы можете поиграть с примером по ссылке

6.Эффекты наложения слоев

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

<article class="card">

  <h3 class="card__title">Карточка с котом на фоне</h3>

</article>

.card {

  display: flex;

  align-items: flex-end;

  box-sizing: border-box;

  position: relative;

  padding: 35px;

  width: 400px;

  min-height: 300px;

  background-image: url(https://www.xaprb.com/media/2018/08/kitten.jpg);

  background-position: center;

  background-size: cover;

  background-repeat: no-repeat;

}

.card__title {

  position: relative;

  z-index: 5;

  margin: 0;

  color: #fff;

}

.card::before {

  content: "";

  position: absolute;

  top: 0;

  left: 0;

  bottom: 0;

  right: 0;

  box-shadow: inset 2px -148px 103px -5px rgb(26 26 26 / 90%);

}

Здесь два важных момента - стили заголовка и стили самого псевдоэлемента. Итак, у заголовка задан белый цвет текста, и как вы понимаете, если картинка на фоне будет светлая - текст мы не увидим. Поэтому нужно затемнение.

Чтобы затемнение было под текстом, мы просто поднимем текст - дадим ему position:relative и z-index больше нуля.

Само затемнение, конечно, делаем псевдоэлементом. С помощью position: absolute и свойств top, left, right, bottom со значением 0 мы растягиваем псевдоэлемент на размер родителя, и просто даем ему тень. Получается затемнение.

Вы можете поиграть с примером по ссылке

7.Стилизация кавычек у цитаты

У тега q (тег для небольшой цитаты) по умолчанию есть свои кавычки (кстати, они сделаны псевдоэлементом), которые в 99% случаев не подходят к общему стилю страницы. Раз они уже сделаны через псевдоэлементы - мы легко можем заменить их на свои.

Помимо тега q есть еще и blockquote, который кавычек не имеет. Но если очень хочется, их можно сделать. Пример:

<blockquote class="quote">

  Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis, officia?

</blockquote>

<q class="quote">Далеко-далеко за словесными горами в стране.</q>

body {

  padding: 100px;

}

.quote {

  margin: 0;

  margin-bottom: 100px;

  display: block;

  width: max-content;

  position: relative;

}

.quote::before {

  content: open-quote;

  top: 0;

  left: 0;

}

.quote::after {

  content: close-quote;

  bottom: 0;

  right: 0;

}

.quote::before,

.quote::after {

  line-height: 1.5;

  font-size: 3em;

  text-align: center;

  position: absolute;

}

Я специально показал здесь и q, и blockquote, чтобы было понятно, что стилями возможно все. Для разных тегов можно написать легко одно и то же.

В общем-то, сейчас кавычки сделаны через content: open-quote, но если хочется - можно использовать бэкграунд-изображение, чтобы сделать абсолютно любые кавычки.

Вы можете поиграть с примером по ссылке

8.Стилизация атрибута alt

Довольно специфический, но иногда очень удобный прием. С помощью псевдоэлемента можно исправить стандартное некрасивое отображение “сломанной” картинки на нормальное.

как выглядит стандартный alt, если картинка не загрузилась.

а так мы можем сделать

Давайте разберем пример:

<div class="image">

  <img src="https://www.xaprb.com/media/2018/08/kittenы.jpg" alt="Спящий кот">

</div>

body {

  padding: 100px;

}

.image {

  position: relative;

  width: 400px;

  height: 300px;

}

img {

  max-width: 100%;

}

.image img::before {

  content: attr(alt);

  position: absolute;

  left: 0;

  right: 0;

  top: 0;

  bottom: 0;

  z-index: 5;

  display: flex;

  align-items: center;

  justify-content: center;

  font-weight: bold;

  font-size: 20px;

  background-color: wheat;

} 

Самое важное тут - это интересная особенность свойства content. Внутри можно размещать значение атрибутов тега, и это здорово. Например, вы могли бы сделать свои собственные data-атрибуты с каким-то текстом, и вывести его на сайт с помощью content: attr().

Вы можете поиграть с примером по ссылке

9.Геометрические эффекты стилизации (линии, кружочки и т.д.)

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

<h2 class="title">Далеко-далеко за словесными горами в стране.</h2>

body {

  padding: 100px;

}

.title {

  text-align: center;

  margin: 0;

  padding-bottom: 30px;

  position: relative;

}

.title::after {

  content: "";

  position: absolute;

  left: 50%;

  bottom: 0;

  width: 70px;

  height: 2px;

  background-color: crimson;

  transform: translateX(-50%);

}

Здесь создается псевдоэлемент с пустым контентом, с указанием размеров (ширины и высоты) и фона (background). По сути мы нарисовали прямоугольник, который выглядит как линия.  

Точно также  можно делать круги, квадраты и прочие фигуры, которые есть в макете.

Вы можете поиграть с примером по ссылке

10.Эффекты для состояний элементов

Для состояний элементов (hover, focus, active) можно использовать псевдоэлементы, особенно если эти эффекты нестандартные, со скруглением углов и так далее. Снова посмотрим пример:

<button class="btn-reset btn">Кошелёк</button>

body {

  padding: 100px;

}

.btn-reset {

    border: none;

    padding: 0;

    background-color: transparent;

    cursor: pointer;

}

.btn {

    box-sizing: border-box;

    outline: none;

    position: relative;

    border-radius: 100px;

    padding: 17px 32px;

    font-weight: 700;

    font-size: 16px;

    line-height: 16px;

    color: #fff;

    background-color: #111;

    transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;

}

.btn::after {

    content: "";

    box-sizing: border-box;

    position: absolute;

    left: -6px;

    top: -6px;

    border: 2px solid wheat;

    border-radius: 100px;

    width: calc(100% + 12px);

    height: calc(100% + 12px);

    opacity: 0;

}

.btn:focus::after {

  opacity: 1;

}

Здесь создается псевдоэлемент с размером на 12 пикселей большим, чем у родителя. Затем перемещаем его на 6 пикселей, и псевдоэлемент встает четко по центру элемента.

Через псевдокласс :focus визуализируем его, так что получается красивая обводка.

Вы можете поиграть с примером по ссылке

Вывод

В целом, при помощи псевдоэлементов можно выполнять практически любые преобразования и трансформации, если творчески подойти к процессу. Самое важное здесь то, что при использовании этих элементов разметка не раздувается, поскольку отпадет необходимость использования пустых тегов (как часто делают, используя span). Используйте псевдоэлементы, они серьезно упростят вашу жизнь. Удачи!

На курсе «Веб-вёрстка» вы познакомитесь со стандартами Web 2.0, научитесь работать с макетами и форматировать код, освоите адаптивную вёрстку, а по итогу — сможете создавать быстрые и удобные сайты, которые точно понравятся пользователям. Посмотреть программу и записаться по ссылке.

Комментарии (8)


  1. idelgujin
    01.12.2021 05:44
    +2

    Вот про счётчик не знал, интересно


  1. mamchyts
    01.12.2021 07:20
    +11

    Очень не хватает картинок, учитывая что статья про CSS


  1. KoMaTo3
    01.12.2021 08:02
    +2

    И плюсом псевдоэлементы избавляют от лишних мусорных div, крайне удобная штука, но иногда не хватает, что их всего два.


  1. InformBest
    01.12.2021 12:52

    Спасибо! Сохранил себе. Поддержу насчёт картинок, каждый раз в песочницу приходится заходить.


  1. egoism
    01.12.2021 12:52
    +2

    По первому пункту достаточно использовать

    ::before {
    	content: url(//img.url)
    }


  1. ya_ne_znau
    01.12.2021 21:03

    в стране

    А в какой стране, мы с вами никогда не узнаем)


    1. ImKremen
      08.12.2021 14:38

      В стране гласных и согласных


  1. Aleksei_Segodin
    08.12.2021 16:06

    content: attr(alt) не работает в Сафари.