Как условно применять CSS на основе поддержки At-правил

Веб-функции: at-rule()

Используйте @supports at-rule(@<at-rule name>) {…}, чтобы условно применять определенные правила или объявления CSS, только если браузер поддерживает определенное правило. Оно может содержать правила целиком или использоваться вместе с вложенными стилями CSS, чтобы условно применять определенные объявления.

.foo {
  background: var(--accent-color);

  @supports at-rule(@property) {
    background-image: var(--rainbow-gradient);
    animation: sliding-rainbow 1s linear infinite;
  }
}

НЕ используйте @supports at-rule(), чтобы условно применить только обнаруженное правило.

/* BAD: CSS already ignores rules the browser doesn't understand, so this is unnecessary */
@supports at-rule(@starting-style) {
  @starting-style {
    /* ... */
  }
}

Определение поддержки at-правил, когда @supports at-rule() не подходит

Если at-rule() не поддерживается браузером или требуется более глубокий анализ, воспользуйтесь приведенными ниже рекомендациями.

Сначала попробуйте свойства, значения или селекторы.

@supports уже может обнаруживать свойства, значения и селекторы (через @supports selector(...)). Во многих случаях вы можете использовать их, чтобы определить, поддерживается ли функция, не проверяя само правило.

Например, вместо @supports at-rule(@function) для обнаружения поддержки пользовательских функций можно использовать @supports (color: --foo()).

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

Определение типов запросов контейнера

at-rule() позволяет обнаруживать at-правила только по названию. Он НЕ позволяет обнаруживать другие синтаксические конструкции или дескрипторы. Например, следующий вариант работать не будет:

@supports at-rule(@container style(--a: 1)) {
  /* ... */
}

Для многих типов запросов контейнера можно использовать container-type с подходящим значением. Например, @supports (container-type: scroll-state) для запросов состояния прокрутки или @supports (container-type: size)container-type: anchoredforanchored()`.

Однако для запросов стиля container-type не существует. ВАЖНО! НЕ пытайтесь использовать @supports (container-type: style) для определения поддержки запросов стилей, так как это не сработает.

Вместо этого вы можете попробовать запрос стиля, который всегда верен:

@container style(--a: 1) or (not (style(--a: 1))) {
  /* Rules here will only be applied if style queries are supported */
}

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

Зарегистрированные пользовательские свойства (@property)

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

/* Use a custom property to conditionally include the dash animation */
@property --progress-dash-animation {
  syntax: "*";
  inherits: false;
  initial-value: , progress-dash 3s ease-in-out infinite;
}

.spinner {
  /* The dash animation is only included if @property is supported */
  animation:
    progress-spin var(--_used-spinner-duration) linear infinite
    var(--progress-dash-animation, );
}

Для более общего решения вы можете зарегистрировать ненаследуемое свойство и задать для него значение (пробел) в корневом элементе:

{# Тестовый пример: https://codepen.io/leaverou/pen/KwWzpVr #}

@property --supports-atproperty {
    syntax: "*";
    inherits: false;
}

:root {
    --supports-atproperty: ;
}

body {
  /* The background is only applied if @property is supported */
    background: var(--supports-atproperty, green);
}

Примечания

  • Оба варианта работают, только если пробел является допустимой альтернативой. В остальных случаях вам потребуется использовать JS, как описано ниже.
  • Решение общего назначения зависит от ненаследования, поэтому оно не будет работать для объявлений в корневом элементе.

Использование JavaScript в крайнем случае

Чтобы проверить поддержку целых at-правил, проверьте наличие определенных интерфейсов в JavaScript. Например, если определено globalThis.CSSFunctionRule, то поддерживается @function.

Если вам нужно провести более глубокое тестирование (например, для определенных прелюдий, вложенных правил, дескрипторов), вы можете настроить тест и проверить, как он был проанализирован:

const sheet = new CSSStyleSheet();
sheet.replaceSync(`
  @page {
    @top-left {
      content: "test";
    }
  }
`);
const SUPPORTS_PAGE_MARGINS = Boolean(sheet.cssRules[0]?.cssRules?.[0]);

ВАЖНО!

  • Если вы используете JS для определения поддержки функций CSS, НЕ применяйте стили непосредственно из JS. Вместо этого примените класс к корневому элементу и создайте ответвление в CSS.
  • Обратите внимание, что запросы контейнеров анализируются, даже если прелюдия не распознается, и нет способа обнаружить поддержку определенных типов запросов контейнеров из структуры CSSOM.
  • НЕ используйте CSS.registerProperty для проверки поддержки @property, так как у него более широкая поддержка.

Резервные стратегии

Если это не входит в ваши цели поддержки, используйте @supports (at-rule()) ТОЛЬКО для обнаружения at-правил, поддержка которых уже, чем у самой функции @supports (at-rule()).

Чтобы условно применять CSS на основе поддержки at-правил, которые поставлялись до этой функции, используйте руководство в разделе выше.

Чтобы определить поддержку @supports at-rule() самой по себе, можно использовать at-правило, которое гарантированно существует во всех браузерах, поддерживающих @supports at-rule(), например @supports at-rule(@media) { ... }.