Masquer et détourer en CSS

Il est devenu compliqué de s'y retrouver dans le paysage changeant du clipping et du masking. Évolution des syntaxes, technologies, support... Chris Coyier fait le point, explications et illustrations claires.

Par

Masquer (masking) et détourer (clipping) sont deux façons de cacher certaines parties d’un élément et d’en montrer d’autres. Il y a bien entendu des différences entre les deux. Différences de possibilités, de syntaxe, de technologies impliquées, nouvelles ou obsolètes, et des différences de compatibilité navigateurs.

NdT : dans la suite de cet article on utilisera les termes clipping et masking qu’on retrouve dans la syntaxe CSS.

Différence entre clipping et masking

Les masques sont des images. Les clips sont des chemins.

Imaginons une image carrée qui serait un dégradé de gauche à droite allant du noir au blanc. Ça pourrait être un masque. L’élément auquel il s’applique sera transparent là où nous avons du noir dans notre masque, et opaque (normal) là où nous avons du blanc. Le résultat final sera donc un élément qui apparaît progressivement (fade-in) de gauche à droite.

Les clips, eux, sont toujours des chemins vectoriels. En dehors du chemin, tout est transparent, à l'intérieur tout est opaque.

J'ai toujours trouvé ça un peu confus, parce que souvent on tombe sur des tutoriels qui illustrent le masking avec une image blanche se découpant sur un fond noir (ou équivalent), c’est à dire d’une façon qui ne le distingue pas du clipping. Pas de problème à ça, mais ça rend juste les choses un peu confuses.

Le clip obsolète

La première apparition du clipping en CSS (à part overflow: hidden; ...naaan c’est une blague !) a été la propriété clip.

Elle ressemblait à ceci :

//CSS
.element {
  clip: rect(10px, 20px, 30px, 40px);
}

Ces quatre valeurs sont données dans le même ordre que pour les margin et padding, c'est à dire dans l’ordre des aiguilles d'une montre en partant du haut :

  • 10px à partir du haut de l’élément
  • 20px à partir de la doite
  • 30px à partir du bas
  • 40 px à partir de la gauche

La propriété clip est obsolète en CSS, ce qui signifie que son utilisation n’est pas recommandée car il existe une nouvelle version standardisée sur laquelle les navigateurs concentrent aujourd’hui leurs efforts.

clip a toutefois des atouts : du fait qu’elle a été utilisée par les navigateurs, elle fonctionnera sans doute toujours. La compatibilité navigateurs est très forte, à peu près tous les navigateurs que vous pouvez imaginer. J’ai même entendu dire que ses performances en termes d’animation dépassent certaines méthodes plus récentes.

Cela dit, clip a aussi des faiblesses :

  • clip ne fonctionne que si l’élément est positionné de façon absolue
  • clip ne peut faire que des rectangles.

Assez limité. Donc passons à l’actualité.

Le nouveau clip-path

La nouvelle façon recommandée d’appliquer un clipping aux éléments CSS est clip-path. On pourrait penser que ce serait aussi facile que ça :

//CSS
.element {
  /* HÉLAS NON */
  clip-path: rect(10px, 20px, 30px, 40px);
}

Cela ne fonctionne pas (nulle part, même avec un préfixe). Apparemment ça deviendra rectangle() mais c’est repoussé à plus tard.

La nouvelle façon de le faire consiste à utiliser inset() :

//CSS
.element {
  clip-path: inset(10px 20px 30px 40px);
  /* Also can take single values to make all sides the same, or 2 values (vert/horz), or 3 values (top/horz/bottom). */
}

Remarquez qu’il n’y a pas de virgule et que la syntaxe est différente, mais au bout du compte on obtient le même résultat.

Ce qui marche également avec clip-path (dans quelques navigateurs), ce sont les cercles, les ellipses et les polygones. En voici quelques exemples :

//CSS
.clip-circle {
  clip-path: circle(60px at center);
  /* AUTREFOIS (p.ex.): circle(245px, 140px, 50px); */
}
.clip-ellipse {
  clip-path: ellipse(60px 40px at 75px 30px);
  /* AUTREFOIS (p.ex.): ellipse(245px, 80px, 75px, 30px); */
}
.clip-polygon {
  clip-path: polygon(5% 5%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
  /* Notez que les pourcentages et les px fonctionnent tous les 2*/
}

Voici quelques exemples dans ce CodePen :

See the Pen NPrdXr by Pierre Choffe (@pierrechoffe) on CodePen.

On peut faire énormément de choses avec les polygones. Ryan Scherf a écrit un article dans CSS-Tricks pour montrer comment on peut les utiliser pour créer un effet d’esquisse dessinée. Mais je vous recommande de les essayer avec Clippy de Bennet Feely (en ligne).


image

Théoriquement, voici ce que clip-path supporte (connu comme “formes basiques”) :

//CSS
.clip-examples {

  clip-path: rectangle(x, y, width, height, rounded-x, rounded-y)

  clip-path: inset-rectangle(from top, from right, from bottom, from left, rounded-x, rounded-y)
  /* Ressemble à ce qu'était rect() avec clip */
  /* Remplacera inset(), je suppose */

  clip-path: polygon(un, tas, de, points)
  clip-path: circle(radius at x, y)
  clip-path: ellipse(width, height at x, y)

}

Je ne trouve pas d’info qui me dise si path() sera un jour une valeur acceptée.

Utiliser clip-path avec un <clipPath> SVG

Vous n’avez pas besoin de définir la valeur de clip-path dans votre CSS, elle peut référencer un élément <clip-path> défini en SVG. Voici à quoi ça ressemble :

//HTML
<img class="clip-svg" src="harry.jpg" alt="Harry Potter">

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      <circle cx="100" cy="100" r="40" />
      <circle cx="60" cy="60" r="40" />
    </clipPath>
  </defs>
</svg>

et le CSS :

//CSS
.clip-svg {
  clip-path: url(#myClip);
}

Démo :

See the Pen LEZxQM by Pierre Choffe (@pierrechoffe) on CodePen.

Sara Soueidan a une démo pour cela également.

L’utilisation des clip-paths définis en SVG pose toutefois un problème important : ils sont accrochés par le coin supérieur gauche du document. Voici une démo de ce problème :

See the Pen emzgry by Pierre Choffe (@pierrechoffe) on CodePen.

Il me manque peut-être une info, mais je ne trouve pas de façon évidente pour faire que le chemin se déplace en même temps que l’élément auquel il est appliqué, contrairement à ce qui se passe si on utilise un élément basique avec CSS.

Animer/Transitionner clip-path

Lorsqu’on déclare une forme basique en tant que clip-path, on peut l’animer ! Dirk Schulze a écrit un bel article à ce sujet, on y trouve cette démo :

See the Pen Wonderful clip-path animation by Chris Coyier (@chriscoyier) on CodePen.

Et voici un exemple simple de code :

//CSS
div {
  transition: 0.4s cubic-bezier(1, -1, 0, 2);
  clip-path: polygon(50% 5%, 0% 100%, 100% 100%);
}
div:hover {
  clip-path: polygon(50% 19%, 0 76%, 100% 76%);
}

Vous pouvez l’essayer ici :

See the Pen wBWgXG by Pierre Choffe (@pierrechoffe) on CodePen.

Masking

Il existait une version WebKit de masking où on pouvait lier une image ou définir un dégradé comme un masque. Ça ressemblait à ceci :

//CSS
img {
  width: 150px;
  -webkit-mask-image: -webkit-gradient(
    linear, left top, right bottom, 
    color-stop(0.00,  rgba(0,0,0,1)),
    color-stop(0.35,  rgba(0,0,0,1)),
    color-stop(0.50,  rgba(0,0,0,0)),
    color-stop(0.65,  rgba(0,0,0,0)),
    color-stop(1.00,  rgba(0,0,0,0)));
}

Pour autant que je sache, cette version est obsolète. On y trouve la syntaxe obsolète des dégradés et quand j'ai essayé de l’utiliser avec la nouvelle syntaxe des dégradés ça n’a pas fonctionné. Donc, oui, sans doute obsolète. Mais ça marche quand même :

See the Pen Old School WebKit Masking by Chris Coyier (@chriscoyier) on CodePen.

et ça a donné lieu à des tutoriels comme WebKit Image Wipes, qui fonctionne toujours (au pays de Blink et de WebKit).

Les versions plus modernes que j'ai trouvées ne mentionnent mask que comme étant défini en SVG et référencé en CSS par leur ID ou leur URL. Voici un exemple utilisant les deux méthodes. Le masque est défini dans le SVG, et à gauche l’image est à l'intérieur du SVG dans une balise. À droite, ce masque est appliqué à une image dans le HTML (ça ne fonctionne apparemment que sous Firefox actuellement).

See the Pen VYjPdO by Pierre Choffe (@pierrechoffe) on CodePen.

Regardez cette démo extraite de l’article de Dirk Schulze (dans Firefox également). Ce genre de choses est un peu dangereux pour l’instant, car non seulement ça ne fonctionne pas dans Webkit/Blink mais ça efface totalement l’élément auquel ça s’applique.

Vous pouvez également faire un lien vers le fichier svg qui deviendra le masque :

//CSS
.mask {
  mask: url(mask.svg);
}

Types de masques

//CSS
.mask {
  mask-type: luminance; /* white = transparent, grays = semi-transparent, black = opaque */
  mask-type: alpha; /* transparent areas of the image let image through, otherwise not */
}

Masques de bordures

Ils fonctionnent de manière assez similaire aux border-image en CSS. On définit une image SVG, et un découpage en 9 est appliqué.

//CSS
.border-mask {
  /* Note that the properties aren't quite the same */
  -webkit-mask-box-image: url(stampTiles.svg) 30 repeat;
  mask-border: url(stampTiles.svg) 30 repeat;
  /* Image, again, from http://www.html5rocks.com/en/tutorials/masking/adobe/ */
}

Voici une démo avec d’un côté un masquage habituel et de l’autre un masque de bordure :

See the Pen Masking in CSS with SVG Image by Chris Coyier (@chriscoyier) on CodePen.

Compatibilité navigateurs

Il est difficile de résumer la compatibilité étant donné les différents niveaux de support des propriétés mais aussi des valeurs elles-mêmes entre les navigateurs. Sans parler de la façon dont vous les utiliserez et sur quoi. C’est un peu l’Ouest sauvage par là, je vous recommande de les utiliser comme amélioration progressive pour l’instant. Ce qui ne sera pas facile car il n’y a même pas de tests Modernizr pour ça.

Pour ce qui est des préfixes, utilisez la version non préfixée et la version préfixée -webkit- pour tout.

Yoksel a réalisé un tableau des comptabilités navigateurs pour nous aider :

See the Pen CSS and SVG Masks by yoksel (@yoksel) on CodePen.

Pour en savoir plus :


Intéressé par CSS ? Sur la Cascade, retrouvez des articles et ressources.


original paru le dans CSS-Tricks.

Sur l'auteur : est designer, blogger, conférencier. Créateur de CSS-Tricks, de CodePen, animateur du Podcast Shop Talk, il est l'auteur avec Jeff Starr de "Digging into WordPress". Vous pouvez le retrouver sur Twitter, Google+.

NdT : CSS-Tricks est un site ressource d'une richesse exceptionnelle, axé sur CSS et le web design en général. Vous pouvez suivre son actualité sur Twitter, Facebook, YouTube, GitHub. Mélange d'articles, de vidéos, de forums, de ressources diverses (jetez un coup d'oeil à son "Almanac" ), il est très populaire sur le web anglophone.

CodePen est un site où vous pouvez tester votre code, faire des maquettes, proposer vos dernières créations et recueillir les observations de vos pairs. C'est aussi une source d'inspiration pour vos propres designs.

Traduit avec l'aimable permission de CSS-Tricks et de l'auteur.
Copyright CSS-Tricks © 2014.