Инструменты разработчика

CSS :has() in 2026 for Static HTML, Safari Sign-Off, and Cloud Mac QA

MacHTML Lab2026.04.02 около 14 мин чтения

Статические маркетинговые страницы и сайты документации по-прежнему поставляют горы рукописного HTML. До недавнего времени стилизовать родителя по состоянию потомка означало лишний JavaScript или неуклюжие обёртки-классы. Реляционный псевдокласс :has() переворачивает логику: секция может сменить рамку, когда внутри отмечен чекбокс, или строка формы подсветится при невалидном поле — без бандлера и часто без единой строки JS. В 2026 году покрытие Safari 15.4+ достаточно широко, чтобы многие команды использовали :has() для визуальных подсказок, если вы проверяете в настоящем WebKit и контролируете сложность селекторов. Руководство описывает практические шаблоны, матрицу решений относительно JS и container queries, а также встраивание проверок в рабочий процесс QA Safari на арендованном Mac mini.

Что :has() даёт на статических страницах

Классический CSS мог стилизовать потомков по предкам (.theme-dark .card), но не наоборот. Продуктовые команды обходили ограничение дублирующими классами в React или зеркалированием состояния детей в data-*. На статических сайтах без JS — юридические тексты, микросайты API, лендинги мероприятий — это мешало тонкой полировке UX. :has() формулирует намерение напрямую: «эта карточка в ошибке, потому что содержит .error-text». Команды доступности по-прежнему ждут видимые подписи и ARIA где нужно; :has() отвечает за оформление, а не за замену семантики.

Поскольку :has() декларативен, дизайнеры пробуют селекторы в CodePen и отгружают те же правила через Eleventy или Hugo без гидратации. Плата — когнитивная: реляционные селекторы сильны и легко перегружаются вложенностью. Введите правило вроде «не больше двух комбинаторов после :has() в маркетинговых шаблонах», чтобы будущие сопровождающие уверенно пользовались grep.

Не привязывайте :has() к корням порталов, которые часто монтируются и снимаются; даже на статике оверлей поиска меняет DOM. Держите корни :has() у карточек, групп полей и стабильных секций таблиц. Многоязычные сайты проверяйте на каждом языке: длина перевода влияет на совпадения селекторов.

Шаблоны синтаксиса

Начните с автономных компонентов. Группа полей, которая светится при фокусе любого контрола:

.field-group:has(:focus-visible) {
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.35);
}

Строка таблицы, помечающая отсутствующие переводы, если в ячейке стоит токен-заглушка:

tr:has(td[data-missing="true"]) {
  background: rgba(255, 59, 48, 0.08);
}

Сочетайте с :not() для исключающих состояний, помня, что пустое значение в чистом CSS выражается слабее, чем в Constraint Validation API. Если бизнес-правила шире атрибутных селекторов, добавьте короткий скрипт с классами вместо десятиусловной цепочки :has().

В тёмной теме :has() можно сочетать с color-scheme и prefers-reduced-motion, ослабляя тени, когда активен дочерний медиаэлемент и пользователь просит меньше движения. Следите за порядком каскада относительно медиазапросов.

Хронология Safari и заметки по тестам

  • Safari 15.4 (март 2022) выпустил :has() на macOS 12.3 и iOS/iPadOS 15.4, в тон с поддержкой уровня Chromium 105 в других движках.
  • Корпоративные политики всё ещё замораживают macOS до 12.3; если даже 3–4 % выручки идёт с таких сборок, дайте запасной цвет рамки без :has().
  • Исправления WebKit иногда сначала попадают в Safari Technology Preview; при багах с nth-child внутри :has() сравнивайте стабильную версию и STP и перепроверяйте каждый ежемесячный статический релиз.

Зафиксируйте минимальный Safari в README рядом с Node и pnpm, чтобы подрядчики не «чинили» вёрстку, вырезая :has() на неделе дедлайна. Пересматривайте строку каждые шесть месяцев по мере обновления парка Mac.

С CDN-canary можно подмешивать упрощённый CSS старым Safari вместо дублирования HTML. Считайте :has() улучшением: без него контент должен оставаться читаемым, а формы — отправляемыми.

Матрица: :has(), JS или @container

ЗадачаПредпочестьПочему
Подсветить родителя при невалидном ребёнке:has(:invalid)Ноль JS, работает офлайн в статическом HTML.
Перестроить дорожки сетки при смене ширины сайдбара@containerШиринный лейаут — зона container queries, не :has().
Отправить JSON формы и показать ошибки сервераJavaScriptСеть и ARIA live выходят за пределы CSS.
Показать иконку, если отмечен любой чекбокс:has(:checked)Декларативно и доступно при корректных label.
Дросселировать аналитику глубины прокруткиJavaScriptCSS не может безопасно слать маяки.

Когда уместны и :has(), и @container, разделите роли: контейнеры для макро-лейаута, :has() для микросостояний внутри дерева компонента. Навешивать оба плотно на один элемент редко помогает читаемости.

Вместе с container queries схема «кто реагирует на ширину родителя, кто на состояние детей» ускоряет ревью.

Производительность и гигиена селекторов

Браузер пересчитывает реляционные селекторы при изменении потомков. На длинной странице с 4000+ узлов шаблон body:has(.modal[open]) { overflow: hidden; } обычно терпим, но цепочки :has() на частых hover-анимациях — нет. Инвалидация стилей WebKit эффективна для локальных поддеревьев; держите корни :has() рядом с карточками и секциями форм. Если в Performance фиолетовые полосы пересчёта шире 2–3 мс на ноутбуке среднего класса во время «шторма hover», вынесите один класс на обёртку с делегированным слушателем.

Stylelint с лимитами специфичности предотвращает «суп из селекторов». Шаг CI на облачном Mac ловит регрессии только macOS до слияния; аренда Apple Silicon на две недели дешевле пятого MacBook под кампанию.

Безопасность: :has() не читает произвольный текст — только структуру и псевдоклассы, сам по себе это не канал утечки. Не логируйте полные строки селекторов с пользовательскими классами в стороннюю аналитику.

При миграции BEM-модификаторов вроде .card--error спланируйте два спринта перекрытия: класс для аналитики, визуал через :has(), затем удаление модификатора после переезда событий на data-атрибуты. Статические сайты часто экономят 2–4 КБ gzip, убрав лишние toggle-скрипты.

Для печати с :has() отдельно проверьте предпросмотр печати Safari — PDF-архивы могут терять красную рамку на белом фоне.

Чеклист QA на облачном Mac mini

Арендуйте macOS со стабильным Safari, грузите статическую сборку через file:// или локальный сервер и пройдите три сценария: только клавиатура в формах, принудительная невалидность, масштаб 200 % на обрезку. Для баг-башей хватит записи 1280×720 без HAR. Без локальных Mac схема SSH + периодический VNC совпадает с другими статьями Safari.

Mac mini на Apple Silicon остаётся тихим при параллельном линте и профилировании стилей — удобно, если ночью прогоняете двадцать HTML-шаблонов. Облачный доступ позволяет подрядчикам делить одну машину вместо пересылки ноутбуков.

Добавьте дымовой автотест: загрузить страницу, переключать примеры полей между валидным и невалидным, снимать панель вычисленных стилей для корней :has(). PNG рядом с тегом релиза почти не занимают места, но экономят 25–35 минут споров, когда WebKit расходится с Chromium.

FAQ

Какая версия Safari включает :has()?

Safari 15.4 на macOS 12.3 и iOS 15.4 (март 2022). Команды с Safari 14 нуждаются в запасном варианте без :has().

Может ли :has() заменить JavaScript в формах?

Для чисто визуальных подсказок (рамки, иконки) часто да; для текста валидации, ARIA live или серверных кругов всё ещё нужны JS или семантика HTML.

Вредит ли :has() производительности?

Глубоко вложенные цепочки на огромных страницах могут удорожать пересчёт стилей. Локализуйте селекторы, не вешайте :has() на каждый hover маркетинговой страницы на 5k узлов и измеряйте в Web Inspector.

При дисциплине :has() убирает шаблонный код из статического HTML и сохраняет тонкие бандлы. Сочетайте реальные сессии Safari, а не только Chromium, чтобы ловить особенности инвалидации WebKit. Mac mini на Apple Silicon даёт нативный WebKit, низкое энергопотребление в простое и тихую работу для длинных ручных QA. MacHTML сдаёт физические Mac mini с SSH/VNC, чтобы поднять WebKit-лабораторию на окно релиза и потом снизить масштаб — без CAPEX на железо, простаивающее между запусками.

Нужен Safari для QA :has()?

Арендуйте Mac mini на Apple Silicon, запускайте Web Inspector на настоящем WebKit и продолжайте поставлять статический HTML из привычного редактора.

WebKit QA на облачном Mac
От $16.9/день