Mais lorsque Hugo Giraudel a lancé son CSS brain teaser[1] puis précisé sur Twitter qu’il apprécierait une solution utilisant clip-path, je me suis dit : pourquoi pas ?

Les spécifications actuelles 

Ne connaissant que de très loin cette propriété, il a fallu me mettre à jour. clip-path, à l’instar de clip, sert à délimiter la zone d’affichage d’un contenu. Je m’oriente vers les spécifications pour compléter cet embryon de culture — et là, c’est le drame :

On peut d’ores et déjà noter une différence remarquable entre les états de ces deux spécifications : l’une est en brouillon, l’autre en recommandation. La spécification SVG est extrêmement aboutie et claire, les ressources ne manquent pas[2] et la compatibilité de cette technologie est très correcte.

En revanche le module CSS est obscur. Il existe un lien étroit entre les deux spécifications, car le brouillon du module CSS Masking s’appuie énormément sur la spécification SVG — et qu’en SVG il existe l’attribut clip-path. Ça génère des incompréhensions qui ne vont pas faciliter la prise en main de cette propriété.

Pour éclaircir un peu tout ça — et vous épargner la lecture des spécifications — vous devriez pouvoir écrire ceci pour utiliser une forme basique :


.clip {
clip-path: circle( 50%, 50%, 5em );
}

Mais ceci devrait fonctionner également — en appelant un élément SVG :


.clip {
clip-path: url(#circle);
}

Les origines 

Il faut sonder un peu les origines de ce module CSS pour en comprendre l’obscurité. Bien que déjà en cours d’élaboration dans le cadre technique du SVG, la possibilité de masquer des éléments en CSS existait depuis CSS 2.1 grâce à la propriété clip, désormais dépréciée[3].

Cette propriété n’a jamais réellement trouvé son public, car elle a deux inconvénients majeurs :

  1. L’élément masqué doit être en position absolue;
  2. Le masque ne peut être que rectangulaire, et son placement est contre-intuitif.

Embêtant. Constatant les progrès possibles de cette fonctionnalité en CSS, c’est le navigateur Safari qui a ouvert les hostilités en 2008 avec les propriétés -webkit-mask-… supportées dès Safari 4. Cette technique a rencontré un franc succès car elle permet d’utiliser une image comme masque. Malheureusement cette propriété n’était supportée que par le moteur de rendu Webkit[4].

Là, j’ai vu poindre le problème : la spécification CSS en cours d’élaboration mélange joyeusement les clips issus de SVG et la proposition de Safari[5]. La distinction est abordée dès le début du document de spécification, mais je trouve que cette scission reste extrêmement troublante. Le W3C précise que les clips sont recommandés pour des raisons de souplesse et de performance, cependant les masques sont bien plus matures et simples à utiliser — ce qui fait naturellement pencher la balance du côté obscur.

Des ressources dissonantes 

Il est fort peu probable que personne avant moi ne s’y soit intéressé. Et en effet, quatre ressources principales sont indispensables pour appréhender clip-path :

Comme vous vous en apercevrez en les lisant, le contenu est disparate. La compatibilité navigateur est abordée différemment[6], le fonctionnement est vulgarisé avec plus ou moins de réussite[7], les exemples ne respectent même pas le contenu de l’article[8]… C’est le moment ou on re-fait « cocorico » puisque la meilleure ressource est celle en Français, rédigée par Vincent De Oliveira — avec l’avantage d’être également la plus récente.

À l’instar de la spécification qui intègre les clips et les masques, ces ressources présentent les deux techniques. Dommage car deux articles distincts auraient été bien plus clairs !

Un bilan mitigé 

Après avoir compulsé maladivement les spécifications, articles, tutoriaux et autres exemples pendant quelques jours, j’ai abouti à un exemple ressemblant à ceci :


/**
* 1. Définition d’une forme rectangulaire de repli pour les navigateurs ne supportant pas clip-path;
* 2. Création d’une forme SVG basique, circulaire;
* 3. Appel d’un fichier SVG contenant un élément clipPath.
*/
.clip {
clip: rect( 7em, 30em, 17em, 20em ); /* 1 */
-webkit-clip-path: circle( 50%, 50%, 5em ); /* 2 */
clip-path: url(#circle); /* 3 */
}

Évidemment, cela implique un balisage précis côté HTML :


<p class="clip">
♬ Tout, tout, tout : vous saurez tout sur le clip-path ♬
</p>
<svg width="200" height="200">
<defs>
<clipPath id="circle">
<circle cx="50%" cy="50%" r="80" />
</clipPath>
</defs>
</svg>

Ainsi je tente de vous livrer un état des lieux aussi complet que possible[9].

  • Chrome 23, Safari 6.1 et Opéra 15 supportent clip-path sous toutes ses formes — incluant la définition de formes SVG basiques dans le CSS;
  • Firefox 4 supporte clip-path si on référence un élément SVG clipPath — ce qui implique d’ajouter un fichier SVG — en revanche vous serez obligés de définir des positions en unités absolues comme le px pour positionner votre clip si vous souhaitez éviter les bugs, et c’est bien dommage;
  • Opéra 7, Chrome 14, IE8 à 11 et Safari 1 se replient sur clip;
  • Une note sur IE9 à 11 : ces navigateurs supportent clip-path si on référence un élément SVG clipPath, à condition d’appliquer le clip sur un élément SVG. Il est envisageable d’intégrer la zone à clipper dans un élément ForeignObject au sein d’un SVG, mais ça devient trop tordu à mon goût;
  • Un mot sur IE4 à 7 : surpris vous êtes ? Ne le soyez pas, clip est reconnu sur IE4 à 7 (et même Netscape 4). Le hic, ce sont les pseudo-éléments que j’emploie dans mon exemple; ainsi en ajoutant un élément dédié dans le DOM, vous devriez pouvoir supporter IE4 facilement 😀 .

Une solution correcte 

Malgré le support disparate et le funambulisme nécessaire pour aboutir à un résultat viable, j’ai trouvé clip-path extrêmement intéressant — et notamment grâce à la dégradation possible à l’aide de clip sur de très vieux navigateurs et de façon simplissime.

Ce repli implique de perdre les formes personnalisées au profit d’un rectangle « simple », ce qui fut considéré comme acceptable lors de l’avènement de border-radius par exemple. Et je suppose que dans la plupart des cas, cette solution reste acceptable.

Vous trouverez donc ma solution au casse-tête proposé par Hugo sur CodePen, détaillée, commentée, agrémentée de diverses précisions — en Anglais.

Tout retour sera le bienvenu 🙂 .

Mise à jour

Moins d’une semaine avant la publication de mon article, le brouillon du W3C concernant la notation des formes basiques a évolué. Je cite Vincent De Oliveira, qui a partagé l’information avec moi :

Par contre, la notation des basic-shapes ont (encore) changées récemment! 😛 dev.w3.org

Ô joie. Merci à Vincent en tout cas !

  1. Papa, Maman : j’aime les casses-têtes. 
  2. Un petit « cocorico » s’impose pour féliciter Jérémie Patonnier, qui a grandement contribué à la documentation sur le Mozilla Developper Network notamment. 
  3. La propriété est dépréciée mais très bien supportée, et le W3C indique que les agents utilisateurs (navigateurs web) doivent la supporter malgré sa déprécation. 
  4. Je ne compte pas traiter du marronnier de « la guerre des navigateurs » ni du syndrome « Webkit only ». 
  5. Fabriqué par Apple® en Californie. 
  6. La palme revient à HTML5Rocks qui détaille Chrome et Firefox, et oublie les autres. 
  7. Un grand merci à The Nitty Gritty — sponsorisé par Doliprane®. 
  8. Allez Web Platform Docs, on oublie pour cette fois. 
  9. Je tiens à préciser que je n’ai aucune expertise en la matière : ce ne sont la que les conclusions trouvées par un intégrateur lambda. 

Article rédigé par . Modifié le . Mots-clés :  astuces, compatibilité, css, css3, intégration, optimisation, performances, sources.