Appliquer de manière conditionnelle du CSS en fonction de la compatibilité avec les règles @

Fonctionnalités Web : at-rule()

Utilisez @supports at-rule(@<at-rule name>) {…} pour appliquer de manière conditionnelle certaines règles ou déclarations CSS uniquement si une règle @ est compatible avec le navigateur. Elle peut contenir des règles entières ou être utilisée conjointement avec l'imbrication CSS pour appliquer certaines déclarations de manière conditionnelle.

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

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

N'utilisez PAS @supports at-rule() pour appliquer de manière conditionnelle l'at-rule détectée et rien d'autre.

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

Détecter la prise en charge des at-rules lorsque @supports at-rule() n'est pas approprié

Lorsque at-rule() n'est pas une option, soit en raison de la compatibilité du navigateur, soit parce qu'une détection plus approfondie est nécessaire, vous pouvez suivre les conseils ci-dessous.

Essayez d'abord les propriétés, les valeurs ou les sélecteurs

@supports peut déjà détecter les propriétés, les valeurs et les sélecteurs (via @supports selector(...)). Dans de nombreux cas, vous pouvez les utiliser pour détecter la compatibilité avec une fonctionnalité sans avoir à vérifier la règle @ elle-même.

Par exemple, au lieu d'utiliser @supports at-rule(@function) pour détecter la compatibilité avec les fonctions personnalisées, vous pouvez utiliser @supports (color: --foo()).

Dans d'autres cas, il peut y avoir des pseudo-classes ou des pseudo-éléments qui ne sont disponibles que lorsqu'une certaine règle @ est prise en charge, ce qui peut être utilisé pour détecter la compatibilité.

Détecter les types de requêtes de conteneur

at-rule() permet UNIQUEMENT de détecter les règles @ par nom. Il ne permet PAS de détecter d'autres syntaxes ou descripteurs. Par exemple, ceci ne fonctionnera pas :

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

Pour de nombreux types de requêtes de conteneur, vous pouvez utiliser container-type avec une valeur appropriée. Par exemple, @supports (container-type: scroll-state) pour les requêtes d'état de défilement ou @supports (container-type: size)container-type: anchoredforanchored()`.

Toutefois, il n'existe pas de container-type pour les requêtes de style. IMPORTANT : N'essayez PAS d'utiliser @supports (container-type: style) pour détecter la compatibilité avec les requêtes de style, car cela ne fonctionnera pas.

À la place, vous pouvez essayer une requête de style qui est toujours vraie :

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

Cela correspondra à n'importe quel navigateur compatible avec les requêtes de style, quel que soit le nom ou la valeur de la propriété que vous utilisez, à condition qu'ils soient identiques dans les deux cas.

Propriétés personnalisées enregistrées (@property)

Dans certains cas, si le CSS conditionnel à appliquer peut être réduit à une seule propriété, vous pouvez utiliser une propriété personnalisée dédiée enregistrée à cet effet :

/* 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, );
}

Pour une solution plus générale, vous pouvez enregistrer une propriété non héritée et la définir sur (un espace) sur l'élément racine :

{# Testcase: 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);
}

Remarques :

  • Ces deux options ne fonctionnent que si l'espace blanc est une alternative acceptable. Dans les autres cas, vous devrez utiliser JS, comme décrit ci-dessous.
  • La solution à usage général dépend de la non-héritabilité. Elle ne fonctionnera donc pas pour les déclarations sur l'élément racine.

Utiliser JavaScript en dernier recours

Pour les règles @ complètes, vérifiez la présence de certaines interfaces en JavaScript. Par exemple, si globalThis.CSSFunctionRule est défini, @function est accepté.

Si vous avez besoin de tester plus en détail (par exemple, pour certains préludes, règles imbriquées ou descripteurs), vous pouvez configurer un test et vérifier comment il a été analysé :

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

IMPORTANT :

  • Lorsque vous utilisez JS pour détecter la compatibilité avec les fonctionnalités CSS, n'appliquez PAS les styles directement à partir de JS. Appliquez plutôt une classe à l'élément racine et créez une branche à partir de celle-ci en CSS.
  • Notez que les requêtes de conteneur sont analysées même si le prélude n'est pas reconnu, et qu'il n'est pas possible de détecter la compatibilité avec certains types de requêtes de conteneur à partir de la structure CSSOM.
  • N'utilisez PAS CSS.registerProperty pour détecter la compatibilité avec @property, car sa compatibilité est légèrement plus étendue.

Stratégies de remplacement

Sauf si cela correspond à votre cible de compatibilité, utilisez UNIQUEMENT @supports (at-rule()) pour détecter les règles @ dont la compatibilité est plus limitée que la fonctionnalité @supports (at-rule()) elle-même.

Pour appliquer de manière conditionnelle du CSS en fonction de la compatibilité avec les règles @-rules fournies avant cette fonctionnalité, suivez les instructions de la section ci-dessus.

Pour détecter la compatibilité avec la fonctionnalité @supports at-rule() elle-même, vous pouvez utiliser une règle @ qui existe dans tous les navigateurs compatibles avec @supports at-rule(), comme @supports at-rule(@media) { ... }.