---
title: "Comment détecter Safari en CSS ?"
description: "Besoin de cibler Safari en CSS ? Voici une méthode fiable avec @supports, idéale pour gérer les cas de rétrocompatibilité comme le support du gap en flexbox."
url: "https://lonestone.io/blog/comment-detecter-safari-en-css"
---

[Lonestone](/) ⟩ [Blog](/blog)

# Détecter Safari en CSS : les solutions possibles

17 mars 2023 · 12 min de lecture

_**Suivi de comment créer un polyfill pour le gap d’une flexbox**_**‍**

Avant d’aller plus loin, voici la réponse :

```
@supports (background: -webkit-named-image(i)) {} /** Safari */
@supports not (background: -webkit-named-image(i)) {} /** Other browsers */
```

Boum, voilà. Avec ces sélecteurs, vous pouvez déclarer des règles spécifiquement pour Safari, de façon compatible avec n’importe quelle version (à ce jour, de la 3.1 à la 16). Très utile si vous devez résoudre des problèmes de rétro-compatibilité CSS, ou un comportement propre à Safari nécessitant un correctif.

Maintenant si vous souhaitez aller plus loin, laissez-moi vous raconter comment j’en suis arrivé à ce sélecteur. Je vais notamment détailler pourquoi j’en ai eu besoin, ce qu’il fait exactement, et pourquoi il est efficace.

Mais avant cela, je vais devoir vous parler de flexbox.‍

## De la rétro-compatibilité du gap

gap est une propriété CSS permettant de spécifier, sur un parent _flexbox_ ou _grid_, l’écart entre les enfants. C’est un outil très puissant pour l’agencement, bien plus que les marges ! En effet, définir des marges externes (margin) sur un élément le rend difficile à maintenir. Car les marges externes poussent le contenu autour sans discrimination, elles créent des effets de bord au moindre changement de contexte. C’est un enfer à gérer ! **Le style appliqué à un élément ne devrait impacter que ce qui est à l’intérieur de l’élément**. Ainsi margin est une propriété généralement à proscrire, en faveur de padding (quand l’espace interne a du sens) ainsi que, donc, gap. gap permet de faire dire au parent « _Je veux que mes enfants, quels qu’ils soient, soient espacés de cette façon »._ L’agencement devient alors bien plus simple à gérer, **car un espace n’existe qu’entre deux éléments**.

gap est supporté par tous les navigateurs depuis 2020, vous pouvez donc l’utiliser sans risque ! Ça ne coûte rien de rajouter un display: flex sur le conteneur, que celui-ci soit horizontal ou vertical. Vous avez tout à gagner à utiliser cette propriété. Mais qu’en est-il des anciens navigateurs ? Il est possible que vous souhaitiez cibler les versions qui ne supportent pas encore gap, comme ce fut mon cas **Vous allez alors avoir besoin d’un remplacement pour gap.** Bonne nouvelle, il y en a un : le sélecteur > \* + \*. Qui se traduit en « _enfant direct succédant un autre enfant direct »_. De cette façon vous pouvez cibler les enfants qui ont besoin d’un espace en haut (vertical) ou à gauche (horizontal) pour obtenir le bon espacement.

```
.flexContainer > * + * {
  margin-top: 8px;
}
```

_Note : Il est aussi possible d’utiliser les sélecteurs :not(:last-child) ou :not(:first-child). Mais je privilégie la première solution car elle est plus courte et rapidement reconnaissable._

Cette solution n’est toutefois pas parfaite, car elle est moins performante que le gap. Par exemple, elle gère moins bien le _wrap :_ sur le retour à la ligne (ou colonne), la marge est toujours présente et crée un décalage ! Un cas qui est géré par gap, qui permet même d’avoir un espace différent entre lignes et colonnes (row-gap et column-gap). Quand gap est supporté par le navigateur, il vaut mieux l’utiliser. Posons nous alors la question : **comment détecter si gap est supporté ?**

La solution est d’apparence simple : @supports(gap: 0) est exactement ce qu’il nous faut ! Malheureusement il y a un piège. Jetons un coup d’œil aux [navigateurs qui supportent gap](https://caniuse.com/mdn-css_properties_gap). En apparence, gap est supporté depuis 2017 par tous les navigateurs. Vous pouvez le voir en sélectionnant la vue « _**Date relative**_ » de _Can I Use_ (une fonctionnalité que j’ai découverte il y a peu, et extrêmement utile pour la rétro compatibilité comme vous allez le voir). Sauf que nous ne visons pas n’importe quel gap : on utilise celui pour flexbox. La compatibilité pour celui-ci est [une tout autre histoire](https://caniuse.com/flexbox-gap). On table plutôt sur du 2020 (un délai de 3 ans, eh oui), avec des écarts entre les navigateurs : Firefox le supportait dès fin 2018, et Safari a attendu jusqu’à 2021. Il y a donc **des versions de navigateurs qui supportent gap, mais pas pour flexbox.** Et le problème, c’est que même si le support est partiel, @support(gap: 0) renverra tout de même **true**. Et il n’y a aucun moyen de mesurer le support spécifique du gap pour flexbox ! Que faire alors ?‍

![Visuel gap](/.netlify/images?url=_astro%2Fimage-1.D1DYn1RJ.png&w=680&h=609&dpl=69e9deed41371b000857cf89)

## Ciblage de versions

On pourrait décider de ne plus du tout utiliser gap et passer par des margins, mais comme expliqué plus haut, on perd en fonctionnalité. C’est quand même dommage en 2023 d’impacter la majorité des styles des utilisateurs pour gérer la minorité des navigateurs d’avant 2020 ! L’idéal, c’est de gérer une version alternative pour ceux-là, quitte à ce qu’elle soit un peu moins jolie, pour pouvoir offrir aux navigateurs raisonnablement récents la version idéale du site. Mais comment faire sans @supports sur _flexbox gap_ ?

Récapitulons, on veut être capable de détecter :

*   Les versions de Chrome et Edge _avant_ la 84
    
*   Les versions de Firefox _avant_ la 63
    
*   Les versions de Safari _avant_ la 14.1
    
*   Les versions d’Opera _avant_ la 70
    

À défaut de tester flexbox-gap… **Peut-on trouver une autre propriété CSS qui correspond à ces versions ?**

Ça demande un peu de recherche, mais ce n’est pas une tâche insurmontable. On a les versions des navigateurs et leurs dates. Il s’agit donc de parcourir les changelogs des versions ciblées ou les voisines, regarder l’actualité du web en 2020, et vérifier sur _Can I Use_ si la date de compatibilité correspond à la période ciblée. La règle à suivre étant : _**on peut cibler une version légèrement supérieure à celle voulue, mais aucune en-dessous**_. En effet, si une version compatible avec gap utilise les margins à la place, c’est moins dramatique que si on essaye d’appliquer gap sur une version qui ne l’implémente pas encore.

Au bout de finalement peu de recherche, j’ai fini par trouver [la valeur CSS revert](https://caniuse.com/css-revert-value) (permettant d’annuler la valeur d’une propriété pour lui donner celle que l’élément aurait par défaut sans CSS). Elle est disponible en 2020 pile sur les versions 84 de Chrome et Edge, sur la 67 de Firefox, et la 74 d’Opera ! Pour ces navigateurs, **on peut donc utiliser @suports(all: revert) pour déterminer avec fiabilité si le gap de flexbox est supporté** !

Mais il y a un couac : Safari supporte revert depuis 2016 (version 9.1). On est carrément en-dessous de la version désirée ! Pour lui, la règle qui colle à la 14.1 serait plutôt [la fonction lch](https://caniuse.com/css-lch-lab) (une nouvelle représentation de couleur). Problème : Safari est encore le seul à supporter cette fonction. Un @supports (color: lch(0% 0 0)) permettrait donc uniquement pour Safari de détecter le support de gap, mais exclurait totalement les autres navigateurs.

On a donc **deux solutions différentes, pour « deux » navigateurs** (bon, plus précisément, pour Safari et le reste du monde). Pour les appliquer, il faudrait écrire quelque chose dans ce genre :

```
.flexContainer > * + * {
  margin-top: 10px;
}
@supports ({is_safari?}) and (color: lch(0% 0 0)) {
  .flexContainer { gap: 10px; }
  .flexContainer > * + * { margin-top: 0; }
}
@supports (not {is_safari?}) and (all: revert) {
  .flexContainer { gap: 10px; }
  .flexContainer > * + * { margin-top: 0; }
}
```

Il nous faut donc résoudre le problème de l’intitulé : quelle règle CSS permet de détecter Safari, _**ou son absence**_ ?

## Les fausses pistes

Ce problème est loin d’être nouveau, et si vous le recherchez sur internet, vous tombez rapidement sur ce résultat :

```
_::-webkit-full-page-media, _:future, :root .safari_only {
  /* Your Safari only style here */
}
```

Premier résultat sur _StackOverflow_, dans un post qui a le mérite d’être très documenté et liste plein d’exemples et de variations ! Malheureusement dans notre cas, **cette solution ne fonctionne pas**. Pourquoi ? Et d’abord qu’est-ce que ça fait exactement tout ce charabia ?

Le sélecteur utilisé est découpé en trois parties, séparées par des virgules. Il s’agit donc en réalité de trois sélecteurs. Le .safari\_only du troisième fait référence à une classe créée pour l’exemple, il peut donc être remplacé par n’importe quoi, pas besoin de s’étendre dessus. La clé se situe sur les deux premiers sélecteurs, s’appliquant sur un élément \_. Que veut dire l’underscore en CSS ? Absolument rien (je vous épargne la longue recherche). CSS l’interprète comme si l’on ciblait un tag div ou span, sauf qu’ici il cherche un tag \_, qu’il ne trouvera jamais car ça n’existe pas dans le DOM. Et c’est voulu, car ce qui compte, c’est les pseudo-sélecteurs, ::-webkit-full-page-media et :future. Comme vous le devinerez aisément, ceux-ci n’existent que sous Safari (ainsi que quelques versions de Chrome, mais jamais en même temps, d’où la présence des deux). Et voilà la subtilité : **lorsque CSS rencontre une syntaxe qu’il ne reconnaît pas, il ignore le bloc entier et passe au suivant**. C’est l’une des forces d’HTML et de CSS, ils ne plantent jamais même en cas d’erreur. Ici, ça nous permet de forcer CSS à lire la ligne sur Safari, et l’ignorer sur les autres navigateurs ! Plutôt ingénieux.

Seulement ça ne convient pas à notre besoin. Déjà parce qu’on ne peut pas en faire une négation. Comme ce mécanisme fait « planter » silencieusement CSS, même utiliser un :not dessus aurait le même effet. Or on a besoin aussi de sélectionner exclusivement les autres navigateurs que Safari (le StackOverflow présentant cette solution propose aussi des solutions pour Chrome, mais  elles ne s’appliquent pas à Firefox ni Opera, et reposent sur un même type de logique). L’autre problème, ce que cette solution est un sélecteur, et que l’on cherche à utiliser @supports. Il ne nous est donc pas possible de combiner les deux.

Quelque part ailleurs sur internet, il y a un article nommé [CSS @supports rules to target only Firefox / Safari / Chromium](https://www.bram.us/2021/06/23/css-at-supports-rules-to-target-only-firefox-safari-chromium/). Le titre est prometteur, et sa solution d’apparence élégante !

```
@supports selector(:nth-child(1 of x))
```

On a bien un filtre dans @supports, et une règle qu’on peut inverser avec not ! Cette syntaxe :nth-child pour sélectionner le nième enfant parmi x n’existe en effet que sous Safari.  Problème résolu ?

Pas tout à fait malheureusement. Car ce filtre utilise **la fonction selector qui teste la compatibilité d’un sélecteur avec le navigateur.** Un outil très utile à avoir à votre ceinture. Mais avec une mise en garde cependant : [il n’est supporté que depuis 2020](https://caniuse.com/mdn-css_at-rules_supports_selector). Sur la 81 de Chromium, la 14.1 de Edge, et la 69 de Firefox. Ça ne nous arrange pas du tout ! Ce filtre exclue trop de versions pour lesquelles on a besoin de dissocier Safari (et hélas il n’est pas possible de tester @supports (selector)).

Mais dans ce même article, il y a [un tweet](https://twitter.com/simevidas/status/1434843473241329668). Et ce tweet est peut-être le seul endroit sur internet où se trouve la parfaite solution ! (tant que Twitter tient toujours debout)

## La solution

```
@supports (background: -webkit-named-image(i)) {} /** Safari */
@supports not (background: -webkit-named-image(i)) {} /** Other browsers */
```

`-webkit-named-image` est une fonction non standard ajoutée à Safari depuis son premier fork de Chromium en 2008. Il est peu mentionné, mais encore présent sur les versions récentes de Safari ! Inversement, il n’y a absolument aucune chance qu’il soit ajouté sur d’autres navigateurs car c’est une fonction purement propre à Apple. **On a donc là le sélecteur idéal pour dissocier Safari des autres navigateurs** ‍

Cela nous amène donc à la solution finale pour gap :

```
.flexContainer > * + * {
  margin-top: 10px;
}
/* Safari with gap */
@supports (background: -webkit-named-image(i)) and (color: lch(0% 0 0)) {
  .flexContainer { gap: 10px; }
  .flexContainer > * + * { margin-top: 0; }
}
/* Other browsers with gap */
@supports (not (background: -webkit-named-image(i))) and (all: revert) {
  .flexContainer { gap: 10px; }
  .flexContainer > * + * { margin-top: 0; }
}
```

_**Note : Il est possible de faire encore plus court en n’utilisant qu’une seule ligne avec un OR. Cependant cela rendrait le code plutôt indigeste à lire, avec une condition très longue remplie de sélecteurs obscurs et de négation. Il est au final plus clair d’avoir deux blocs distincts “Safari” / “Other browsers”, accompagnés de commentaires pour les identifier.**_

Bonus, avec PostCSS, il est possible définir des _mixins_ pour réutiliser ce code :

```
@define-mixin margin-children-column $height {
  & > * + * {
    margin-top: $height;
  }
}
@define-mixin row-gap $gapHeight {
  @mixin margin-children-column $gapHeight;
  @supports (background: -webkit-named-image(i)) and (color: lch(0% 0 0)) {
    row-gap: $gapHeight;
    @mixin margin-children-column 0;
  }
  @supports (not (background: -webkit-named-image(i))) and (all: revert) {
    row-gap: $gapHeight;
    @mixin margin-children-column 0;
  }
}

.flexContainer {
  dispplay: flex;
  flex-direction: column;
  @mixin row-gap 10px;
}
```

### Épilogue

Comme vous pouvez le constater, parvenir à cette solution en apparence simple a nécessité un long périple ! Un parcours fait de nombreuses tentatives, expérimentations et recherches, qui ne sont ici que survolées (il y aurait encore beaucoup à dire sur ce que PostCSS permet et ne permet pas). Les distributeurs de navigateurs sont peu enclins à s’accorder sur des standards ou même des documentations pour faciliter le développement, et ce genre de connaissance doit encore se partager comme des arcanes secrètes.

Ce que l’on peut retenir de cette mésaventure, c’est :

*   Vérifiez bien la compatibilité d’une fonctionnalité CSS : un résultat positif peut cacher un support seulement partiel
    
*   _**Can I Use**_ peut est très utile pour placer chronologiquement les versions des navigateurs, et ainsi mesurer et cibler la compatibilité
    
*   `@supports` est le meilleur outil pour détecter la compatibilité, mais il a lui-même ses contraintes
    
*   La rétro-compatibilité a souvent un coût insoupçonné, particulièrement avec Safari qui s’éloigne très souvent des standards des autres navigateurs
    
*   Notez `@supports (background: -webkit-named-image(i))` quelque part parce que c’est vraiment bien planqué‍
    

![Comment détecter Safari en CSS ?](/.netlify/images?url=_astro%2Fthumbnail.DhjLKgen.png&w=1132&h=396&dpl=69e9deed41371b000857cf89)

Sommaire

[1 / De la rétro-compatibilité du gap](#de-la-rétro-compatibilité-du-gap) [2 /](#) [3 / Ciblage de versions](#ciblage-de-versions) [4 /](#-1) [5 / Les fausses pistes](#les-fausses-pistes) [6 /](#-2) [7 / La solution](#la-solution)

Sommaire 1 / De la rétro-compatibilité du gap 2 / 3 / Ciblage de versions 4 / 5 / Les fausses pistes 6 / 7 / La solution

Lonestone est une agence qui conçoit et développe des produits web et mobile innovants intégrant de l'IA.

Nos experts partagent leurs expériences sur le blog. Contactez-nous pour discuter de vos projets !

[En savoir plus sur Lonestone](/)

[Parler à un expert](/contact)

![](/_astro/use-case-corner.3qL77H9h.png)

Besoin d'accompagnement ?

Nos experts sont disponibles pour discuter de votre projet.

[Parler à un expert](/contact)

## On continue la lecture ?

[Tous les articles](/blog)

[![Le SEO technique n’est pas une option](/.netlify/images?url=_astro%2Fthumbnail.D7bGGwb3.jpg&w=1920&h=1280&dpl=69e9deed41371b000857cf89)

Le SEO technique n’est pas une option

Le SEO technique est indispensable pour assurer la visibilité de votre site ou web app. Découvrez les bonnes pratiques à connaître pour éviter de disparaître dans les résultats de recherche.



](/blog/le-seo-technique-nest-pas-une-option)[![Le Top 10 OWASP des vulnérabilités API – 2023](/.netlify/images?url=_astro%2Fthumbnail.Bd0nqvsv.png&w=1754&h=959&dpl=69e9deed41371b000857cf89)

Le Top 10 OWASP des vulnérabilités API – 2023

Les 10 failles de sécurité API à connaître selon l’OWASP 2023, avec exemples et bonnes pratiques pour s’en protéger.



](/blog/owasp-top-10-api-2023)[![Nhost, le Backend-as-a-Service open source qui nous a convaincus](/.netlify/images?url=_astro%2Fthumbnail.r3E5Cjl4.png&w=640&h=360&dpl=69e9deed41371b000857cf89)

Nhost, le Backend-as-a-Service open source qui nous a convaincus

Nhost, l'alternative open source à Firebase pour créer un backend complet avec GraphQL, auth, stockage et déploiement, sans se soucier de l'infra.



](/blog/nhost-le-backend-as-a-service-open-source-qui-nous-a-convaincus)

[Tous les articles](/blog)

## Nos guides

### Guide de l'IA générative

[

01\. IA, Machine Learning & Deep Learning



](/ai/deep-learning)[

02\. LLM (Large Language Model) : définition et fonctionnement



](/ai/llm)[

03\. RAG + MCP : Architecture pour agents IA



](/ai/rag-mcp)[

04\. Agents IA : définition et cas d'usage



](/ai/agents-ia)[

05\. Boostez vos logiciels avec l'intégration de l'IA



](/ai/integration-ia)[

06\. Meilleurs outils IA pour les entreprises



](/ai/outils-ia)

### Guide pour créer un SaaS IA

[

01\. Construire un SaaS IA rentable : la méthode qui fonctionne



](/creer-saas-ia/roadmap)[

02\. Comparatif LLM 2026 : quel modèle choisir pour votre SaaS ?



](/creer-saas-ia/comparatif-llm-saas)[

03\. Héberger un SaaS IA en France : performances, coûts et souveraineté



](/creer-saas-ia/heberger-ia)[

04\. Framework d’évaluation IA : pourquoi et comment le mettre en place



](/creer-saas-ia/evaluation)[

05\. MCP (Model Context Protocol) : le standard pour connecter IA et logiciels



](/creer-saas-ia/mcp)[

06\. Bien choisir entre RAG et ses alternatives : ce que personne ne vous explique vraiment



](/creer-saas-ia/rag)[

07\. Comment concevoir un copilote IA qui crée de la vraie valeur dans un SaaS



](/creer-saas-ia/copilote-ia)[

08\. POC IA : comment valider votre idée avant d’investir dans un SaaS IA



](/creer-saas-ia/poc)

### Blog de Lonestone

Retrouvez nos derniers articles sur le développement web, l'IA, le product design et les retours d'expérience de nos projets.

[Accéder au blog](/blog)

Lonestone apporte son expertise product à 200+ grands comptes, PME et startups depuis 11 ans.

Avec notre équipe senior et nos méthodes rodées, vous pouvez comptez sur une livraison rapide d'un produit robuste vraiment utile.

## Nos solutions

[

01\. Intégration IA pour éditeurs logiciels



](/solutions/integration-ia-editeurs)[

02\. Automatisation de process avec IA



](/solutions/automatisation-process-ia)[

03\. Création de SaaS pour startup



](/solutions/creation-saas)[

04\. Développement d'outils internes



](/solutions/developpement-outil-metier)[

05\. Création d'app mobile



](/solutions/creation-app-mobile)[

06\. Création de site web



](/solutions/creation-site-web)[

07\. Création de CRM sur mesure



](/solutions/crm-sur-mesure)

## On discute de votre projet ?

Échange gratuit et sans engagement, directement avec un expert du sujet. Devis sous 48h.

[Demander un devis](/contact) Prendre rdv

Contacter l'équipe  
de Lonestone
