Привет, Хабр!

В CSS огромное количество псевдо-элементов и псевдо-классов. Так много, что я не знаю ни одного фронтендера, который помнит все. Я тоже не исключение из этого правила.

Часто нахожу что-то новое и интересное у зарубежных блогеров, рассказывающих о CSS. Так что неудивительно, что мы с вами упускаем пользу. Это нормально.

Сегодня я пришёл к вам, чтобы это исправить. Мы рассмотрим несколько псевдо-элементов и псевдо-классов, которые, по моему мнению, редко используют. Хотя они принесут немало пользы!

Давайте посмотрим, что я вам подготовил.

Псевдо-класс :focus-within

Я лично не понимаю, почему псевдо-класс :focus-within очень редко используется. Мне кажется, что про него забыли. Срочно исправляю ситуацию.

Данный псевдо-класс помогает нам стилизовать родительский элемент, если пользователь сфокусировался на его дочернем элементе. Это полезно для визуальных задач и улучшения пользовательского опыта.

Я нашёл классный пример, где псевдо-класс :focus-within будет полезен. Для демонстрации я включу псевдо-класс :focus-visible, как будто пользователь сфокусировался на ссылке.

<article class="js-active js-material-list__blogpost material-list__item piwikTrackContent">
  <div class="material-list__item-text">
    <time class="time-block time-block_top" datetime="2026-08-16 21:55:00">17 минут назад</time>
    <h2 class="material-list__title">
      <a class="h2 material-list__title-link" href="3440113.html">«Спартак» наконец-то победил «Балтику». Угальде разошелся – хорош и в паре с Даку</a>
    </h2>
    <p> Пропустили после аута Бевеева.
      <!-- здесь счётчик лайков -->
    </p>
  </div>
  <a class="material-list__item-img-link material-list__item-img-link_float_right" href="https://www.sports.ru/football/blogs/3440113.html">
    <!-- здесь превьюшка -->
  </a>
</article>

Мы видим, что обводка появилась вокруг ссылки. Уже здорово, что она есть. Но визуально она выглядит инородно. Мне кажется, было бы лучше, если она обводила весь блок с новостью.

Для этого нужно объявить псевдо-класс :focus-within для родительского элемента.

.piwikTrackContent:focus-within {
  outline: 3px solid currentColor;
}

Согласитесь же, что так лучше? Мы видим ровную обводку без каких-то зигзагов, которая повторяет контур элемента. Красота!

Псевдо-классы :is() и :where()

Периодически нам приходится группировать стили, которые применяются с помощью разных селекторов. Для этого в CSS есть запятая. В большинстве случаев всё отлично работает. Но если селектор сложный, у нас появляется повторяющаяся часть.

Для демонстрации я применю свойство line-height для элементов ul и ol, находящихся в элементе с классом .awesome-container.

.awesome-container ul,
.awesome-container ol {
  line-height: 1.5;
}

Оба селектора содержат селектор по классу .awesome-container. Нам пришлось скопировать эту часть селектора, чтобы браузеры применили стили корректно.

Коллеги, мы можем сократить эту запись! В CSS есть псевдо-классы :is() и :where(). Они группируют селекторы так, что нет дублирования кода.

Перепишем предыдущие стили с помощью псевдо-класса :is().

.awesome-container :is(ul, ol) {
  line-height: 1.5;
}

Но это не всё! Мы также можем группировать псевдо-классы. Например, сделаем это для псевдо-классов :hover и :focus-visible.

.awesome-link:is(:hover, :focus-visible) {
  background-color: pink;
}

.awesome-link:focus-visible {
  outline: 2px solid currentColor;
}

Я использую в своих примерах псевдо-класс :is() чаще из-за нюансов расчёта специфичности. Давайте подробнее на этом остановимся.

Псевдо-класс :where() всегда будет рассчитан со специфичностью 0, 0, 0. Для псевдо-класса :is() браузеры вычислят значение по наиболее специфичному селектору, который был передан.

Для тренировки рассмотрим селектор .awesome-block :is(.list, #block, ul).

.awesome-block :is(.list, #block, ul) {
  background-color: pink; /* специфичность селектора 1, 1, 0 */
}

Как я говорил выше, специфичность псевдо-класса :is() определяется по самому весомому селектору. В нашем примере таким является селектор #block. Следовательно, специфичность равна 1, 0, 0. Далее она прибавляется к специфичности по классу .awesome-block. В результате получаем общую специфичность 1, 1, 0.

Надеюсь, этот нюанс не оттолкнёт вас от использования псевдо-классов :is() и :where(). Как человек, не любящий копирование кода, я безумно рад им. Они помогли мне сделать ещё один шаг к лаконичности, и поэтому я всем их рекомендую.

Псевдо-класс :nth-child()

Конечно же, вы знаете псевдо-класс :nth-child(). Сотни раз вы использовали его. Это бесспорно. Но мне интересно проверить, знаете ли вы некоторые техники, которые можно с ним сделать.

Например, вы слышали, что псевдо-класс :nth-child() можно использовать без привязки к позиции элемента? Если нет, то я как раз подготовил для вас пример.

Мы будем использовать несколько элементов с классом .awesome-block и стилизовать второй среди них.

<body>
  <div>1</div>
  <div class="awesome-block">2</div>
  <div>3</div>
  <div class="awesome-block">4</div>
  <div class="awesome-block">5</div>
</body>
.awesome-block:nth-child(2) {
  background-color: pink;
}

Сейчас мы видим, что стили применились к первому элементу с классом .awesome-block, у которого второй порядковый номер в группе. Так получилось, потому что мы указали значение 2.

Если же удалить класс .awesome-block у второго элемента, то стили уже не применятся.

<body>
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div class="awesome-block">4</div>
  <div class="awesome-block">5</div>
</body>

Как же сделать так, чтобы стили применились ко второму элементу с .awesome-block без привязки к позиции элемента. Например, чтобы он был четвёртым элементом в группе.

Вот для этой задачи есть расширенный синтаксис of S для псевдо-класса :nth-child(). Давайте объявим его, стилизовав второй элемент с классом .awesome-block.

<body>
  <div>1</div>
  <div class="awesome-block">2</div>
  <div>3</div>
  <div class="awesome-block">4</div>
  <div class="awesome-block">5</div>
</body>
:nth-child(2 of .awesome-block) {
  background-color: pink;
}

Пожалуйста, обратите внимание, что у этого элемента четвёртый порядковый номер. Получается, что браузер нашёл элемент без привязки к его позиции в группе.

Ещё одной полезной возможностью псевдо-класса :nth-child() являются диапазоны. Так можно сделать, если указать их друг за другом. Первый псевдо-класс будет работать со счётчиком на увеличение, а второй — на уменьшение.

Для демонстрации напишем стили так, чтобы они применились с четвёртого по седьмой элементы.

<body>
  <div class="awesome-block">1</div>
  <div class="awesome-block">2</div>
  <div class="awesome-block">3</div>
  <div class="awesome-block">4</div>
  <div class="awesome-block">5</div>
  <div class="awesome-block">6</div>
  <div class="awesome-block">7</div>
</body>
.awesome-block:nth-child(n+4):nth-child(-n+7) {
  background-color: pink;
}

Вот такие техники можно использовать с псевдо-классом :nth-child(). Когда я не знал их, я всё решал через добавление новых классов. А оказывается, всё можно было решить без них.

Псевдо-элемент ::file-selector-button

Возможность загрузить файл является очень популярной функцией приложения. В вебе долгое время есть тип file для элемента input. Его ещё постоянно прячут, заменяя красивыми кнопками.

Коллеги, уже несколько лет браузеры хорошо поддерживают псевдо-элемент ::file-selector-button. Он позволяет стилизовать стандартную кнопку, которая появляется при использовании элемента input с типом file. Мы можем добавить цвет, тень, скругление углов и т. д. Всё то же самое, что при стилизации обычной кнопки. Например, я сделал голубую с иконкой крестика.

<body>
  <input class="awesome-uploader" type="file">
</body>
.awesome-uploader {
	font-size: 0;
}

.awesome-uploader::file-selector-button {
  padding: 1.5rem;
  border: 1px solid #2E9AFF;
  border-radius: 0.5rem;

  background-color: #2E9AFF;
  background-image: url(https://www.avito.st/static/ims/design-system-icons\_plus\_square\_common.svg);
  background-repeat: no-repeat;
  background-position: center;

  cursor: pointer;
  text-indent: -100vw;
}

При подготовке к статье я проверил демонстрацию во всех популярных браузерах. У меня всё работало. Но буду честен, что в реальном проекте я такой подход не использовал.

Но если у вас есть личные проекты или вы делаете закрытые системы, то псевдо-элемент ::file-selector-button точно будет полезен.

Псевдо-элемент ::spelling-error

Я постоянно делаю опечатки. Это у меня очень давно. В школе я мог сделать по пятнадцать ошибок в диктанте. Мог сделать три ошибки в одном слове. Проверяя домашнюю работу, мама всё время говорила: «Я с тобой русский язык забуду».

В общем, я постоянно страдаю. По этой причине я не люблю что-то печатать. Хотя разработчики могут немного помочь мне. В CSS есть псевдо-элемент ::spelling-error. Он позволяет стилизовать текст, если в нём есть опечатки.

Давайте посмотрим, как он работает на примере. Я как раз подготовил текст, в котором есть слова с опечатками. Выделим их, добавив свойства background-color и text-decoration.

<body>
  <label for="msg">Ваше сообщение</label>
  <textarea id="msg">
    Привет! Это сообщенее для тех, кто ошибоется при напечатовании текста.
  </textarea>
</body>
textarea::spelling-error {
  background-color: rgba(255, 42, 81, 0.2);
  text-decoration: underline 2px solid rgba(255, 42, 81, 1);
  text-underline-offset: 4px;
}

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

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

Заключение

Давайте подведём итог. В этой статье мы рассмотрели:

  • псевдо-класс :focus-within для визуального улучшения выделения элементов, содержащих интерактивные элементы;

  • как группировать селекторы без дублирования с помощью псевдо-класса :where() и :is();

  • псевдо-элемент ::file-selector-button, позволяющий создавать красивые кнопки загрузки файлов с помощью элемента input с типом file;

  • как можно заставить работать псевдо-класс :nth-child() без привязки к порядковому номеру в группе элементов;

  • диапазоны для стилизации элементов с помощью псевдо-класса :nth-child();

  • выделение слов с опечатками с помощью псевдо-элемента ::spelling-error.

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

На этом всё. Спасибо за чтение!

P. S. Помогаю больше узнать про CSS и дружелюбные интерфейсы в своих ТГ‑каналах CSS isn't magic и UX + Dev = a11y. Присоединяйтесь. Как вступить, написано в профиле.

© 2026 ООО «МТ ФИНАНС»

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


  1. k12th
    25.08.2026 09:55

    .awesome-container ul,
    .awesome-container ol {
      line-height: 1.5;
    }
    

    А нестинг не то же самое? И даже более читаемо, кмк. Хотя поддержка у :is получше, конечно.


  1. Metotron0
    25.08.2026 09:55

    псевдо-элемент ::file-selector-button. Он позволяет стилизовать стандартную кнопку

    А как вы убрали надпись No file selected, которая потом заменяется именем файла?