Перейти к содержанию

Псевдокласс :not()

Определение

:not() – CSS-псевдокласс отрицания: выбирает элементы, не соответствующие селектору-аргументу. В Selectors Level 4 принимает список селекторов (:not(.a, .b)) – кроссбраузерно с января 2021 (Chrome 88, Firefox 78, Safari 9).

3 мин 40 Обновлено 12 августа

Исключения – постоянная часть работы со стилями: «все поля, кроме чекбоксов», «все элементы списка, кроме последнего», «все кнопки, кроме основной». Без псевдокласса отрицания такие задачи решаются вторым правилом, перекрывающим первое, или лишними классами в разметке. :not() переносит исключение прямо в селектор. Псевдокласс появился ещё в Selectors Level 3 в урезанном виде, а в Selectors Level 4 стал полноценным инструментом со списком селекторов в аргументе. Вместе с реляционным :has() он образует логику современных селекторов: :has() проверяет наличие, :not() – отсутствие.

Как это работает

Синтаксис – селектор:not(аргумент): правило применяется к элементам, которые не соответствуют ни одному селектору из аргумента. p:not(.fancy) – «параграфы без класса fancy», input:not([type="checkbox"]) – «все поля ввода, кроме чекбоксов». Возможности аргумента зависят от поколения спецификации.

:not() в Selectors Level 3 и Level 4 – в чём разница

Два поколения синтаксиса :not()
ПараметрLevel 3Level 4
Аргументодин простой селекторсписок через запятую, составные и сложные селекторы
Примеры:not(.foo):not(.foo, .bar), h2 :not(span.foo), a:not(table a)
Поддержкавсе браузеры, включая IE9Safari 9 (2015), Firefox 78 (2020), Chrome и Edge 88 (январь 2021)
Обход для старых браузеровне нуженцепочка :not(.foo):not(.bar)

Отсюда типовой вопрос: чем :not(a):not(b) отличается от :not(a, b)? По результату – ничем, оба означают «ни a, ни b». Цепочка – И-логика старого синтаксиса, работающая везде уже больше десяти лет; список – компактная запись Level 4. Ошибка появляется, когда список читают по аналогии с :is(): :not(.foo, .bar) – это «не (.foo ИЛИ .bar)», то есть исключаются оба класса сразу.

Второй важный нюанс: список аргументов :not() – unforgiving («непрощающий»), один невалидный или неподдерживаемый браузером селектор инвалидирует правило целиком. Это прямой контраст с forgiving-списками :is(), :where() и :has(). Приём для устойчивости – обернуть аргументы в :is():

/* База: все параграфы, кроме .fancy */
p:not(.fancy) { color: green; }

/* Level 4: ни .foo, ни .bar */
div:not(.foo, .bar) { color: red; }

/* То же самое в Level 3-синтаксисе */
div:not(.foo):not(.bar) { color: red; }

/* Отступы между элементами списка, кроме последнего */
li:not(:last-child) { margin-block-end: 8px; }

/* Unforgiving-список, защищённый через :is() */
p:not(:is(.foo, :unsupported-thing)) { color: green; }

Специфичность :not() устроена так же, как у :has(): сам псевдокласс ничего не добавляет, считается самый специфичный селектор из аргумента. #foo:not(#bar) выбирает те же элементы, что и просто #foo, но весит как два ID – перебить такое правило почти невозможно. Подробнее о подсчёте – в статье о специфичности CSS.

Зачем это нужно

Главный выигрыш – меньше служебных классов и правил-перекрытий. В дизайн-системах :not() задаёт общие стили «всем, кроме» отдельных компонентов без цепочек переопределений; в шаблонах 1С-Битрикс, где типовые компоненты приходят со своей разметкой, он исключает служебные элементы из общих правил без копирования и правки шаблона. Но у псевдокласса есть ловушки, которые регулярно ловят даже опытных верстальщиков:

  • Матчит html и body. Одиночный :not(.foo) применится ко всем элементам без этого класса, включая html и body, – охват шире ожидаемого. Уточняйте селектор слева: p:not(.foo).
  • Не исключает ветку DOM. body :not(table) a всё равно покрасит ссылки внутри таблицы: между table и ссылкой стоят tbody, tr и td, а каждый из них сам матчит :not(table). В Level 4 задача решается сложным селектором в аргументе: a:not(table a).
  • :not(*) не выбирает ничего. Элемент, который «не элемент», невозможен.
  • Псевдоэлементы запрещены. Передать внутрь ::before или ::first-line нельзя – селектор станет невалидным, аргументом могут быть только селекторы реальных элементов.
Поддержка :not() браузерами
СинтаксисБраузерыСтатус
Один простой селектор (Level 3)все, включая IE9+Baseline Widely available с июля 2015
Список селекторов (Level 4)Safari 9+, Firefox 78+, Chrome и Edge 88+кроссбраузерно с января 2021

Пример

Типовая задача вёрстки – отступы между элементами списка: правило li:not(:last-child) из блока кода выше заменяет пару «всем задать отступ, последнему обнулить» одним селектором. Тот же подход работает с порядковыми псевдоклассами вроде :nth-child(): tr:not(:nth-child(-n + 2)) исключит из правила первые две строки таблицы.

Вторая показательная связка – «отрицание по потомку» вместе с :has():

/* Figure без подписи – убираем нижний отступ */
figure:not(:has(figcaption)) { padding-block-end: 0; }

/* Карточки без изображения получают рамку */
.card:not(:has(img)) { border: 1px solid #e0e0e0; }

До Selectors Level 4 выбрать «элементы, внутри которых чего-то нет» средствами CSS было невозможно – требовался JavaScript, который проверял содержимое и навешивал классы. Сейчас достаточно одного правила, а разметка остаётся чистой: ни классов-модификаторов, ни скриптов, ни рассинхронизации между DOM и стилями.

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

Можно ли передать в :not() несколько селекторов?

Да, начиная с Selectors Level 4 аргументом может быть список через запятую: button:not(.primary, .danger). Поддержка: Safari 9+, Firefox 78+, Chrome и Edge 88+ (январь 2021). Для максимальной совместимости тот же результат даёт цепочка button:not(.primary):not(.danger).

Чем :not(a):not(b) отличается от :not(a, b)?

По результату они эквивалентны: оба означают «ни a, ни b». Разница в поколении синтаксиса и совместимости: цепочка – Selectors Level 3, работает во всех браузерах, включая устаревшие; список – Level 4, кроссбраузерно с января 2021. Важно не путать список с :is(): :not(a, b) исключает оба варианта сразу.

Какая специфичность у :not()?

Сам псевдокласс специфичности не добавляет – считается самый специфичный селектор из аргумента. #foo:not(#bar) матчит те же элементы, что и #foo, но имеет специфичность двух ID. Поэтому ID внутрь :not() без необходимости лучше не передавать.

Почему правило с :not() перестаёт работать целиком?

Скорее всего, в аргументе есть невалидный или неподдерживаемый селектор: список :not() – unforgiving, одна ошибка инвалидирует всё правило. Лечится обёрткой в forgiving-список :is(): p:not(:is(.foo, :experimental)) – невалидная часть просто игнорируется.

Матчит ли :not(.foo) теги html и body?

Да. Без уточняющего селектора слева :not(.foo) применится ко всем элементам без класса foo, включая html и body, – охват получается шире ожидаемого. Указывайте элемент или контекст: p:not(.foo) вместо одиночного :not(.foo).

Почему body :not(table) a красит ссылки внутри таблицы?

Потому что между table и ссылкой стоят tbody, tr и td, а каждый из них сам матчит :not(table). :not() исключает только сам элемент, а не ветку DOM. В Selectors Level 4 задача решается сложным селектором в аргументе: a:not(table a).

Можно ли использовать псевдоэлементы внутри :not()?

Нет, ::before, ::after и другие псевдоэлементы внутри :not() запрещены спецификацией – селектор станет невалидным. :not() принимает только селекторы реальных элементов: теги, классы, атрибуты, псевдоклассы.

Связанные термины

Selectors Level 4 Selectors Level 4 – модуль спецификации CSS от W3C, расширивший селекторы: :is(), :where(), :has(), :not() со списком, :nth-child(An+B of S). Статус – Working Draft (редакция 22.01.2026), но ядро давно поддержано всеми браузерами. Псевдокласс :has() :has() – реляционный CSS-псевдокласс из Selectors Level 4: выбирает элемент по наличию потомка, соседа или состояния внутри. Долгожданный «родительский селектор» работает во всех браузерах с декабря 2023 (Firefox 121). Псевдокласс :nth-child() :nth-child() – CSS-псевдокласс, выбирающий элементы по позиции среди всех детей родителя: по номеру, ключевым словам odd/even или формуле An+B. Нумерация начинается с 1, а не с 0. Специфичность селектора Специфичность селектора – механизм каскада CSS, определяющий, какое из конфликтующих правил применит браузер. Считается триадой A-B-C (ID, классы, теги) и сравнивается попозиционно: один ID тяжелее любого числа классов.

Материалы по теме

Что почитать дальше по этой теме

Статья Что боты находят на сайте, а вы – нет Боты ходят по изнанке сайта, куда живой человек не забредёт, и фиксируют в логах то, чего не видно ни в Метрике, ни на витрине: падающие с ошибкой 500 страницы каталога, битый файл с 747 обращениями, поток сканеров секретов. Разбираю на реальных логах, что искать и как чинить. 7 мин 216 22 июля 2026 Инструкция Как выгрузить и читать access-логи, если хостинг хранит их три дня Access-лог – единственное место, где виден весь трафик сайта, включая ИИ-ботов, которых не замечают счётчики. Разбираю на практике: где взять логи, как не потерять их из-за ротации, какие команды показывают ботов, ошибки и подозрительную активность. 7 мин 170 21 июля 2026 Флагманский гайд AI-анализ email-обращений: методика на стыке Яндекс.Метрики и Claude Code Классический email-трекинг отвечает на вопрос «откуда пришло обращение». AI-слой отвечает на вопросы, которые раньше требовали ручного аналитика: значим ли email на фоне звонков, форм и мессенджеров, почему один источник даёт качественные обращения, а другой – пустые, какие сегменты визитов предшествуют письму, что написать в ответ с учётом пути пользователя. Здесь – как я собираю это на уже имеющемся стеке: Logs API Метрики, PostgreSQL и Claude Code, без новых платных сервисов. 11 мин 297 26 мая 2026 Флагманский гайд Майкор: ИИ-аудит проекта по 4 точкам контакта Майкор – это перекрёстный ИИ-аудит проекта в 4 точках контакта: сайт, контекстная реклама, AI-поиск и Яндекс.Карты. Я анализирую каждую систему и смотрю связки между ними – где маркетинг рассказывает одно, реклама ведёт на другое, а AI-системы цитируют третий номер телефона. В одном из моих аудитов медицинской клиники в Москве у организации в индексе AI-сервисов оказалось 6 разных номеров и всего 7 упоминаний на 64 проверочных запроса – при том, что в обычной выдаче Яндекса клиника была в топ-1. Майкор закрывает такие разрывы за один аудит вместо четырёх раздельных. 16 мин 501 13 мая 2026 Гайд FAQPage Schema: как разметить блок частых вопросов и попасть в AI-ответы FAQPage schema – один из самых эффективных типов разметки для попадания в AI-ответы. Страницы с FAQPage schema цитируются AI-поисковиками в 2,7 раза чаще. В этом гайде – формат разметки, правила написания ответов для AI, реализация на 1С-Битрикс и типичные ошибки, которые обнуляют эффект. 8 мин 331 25 апреля 2026