feColorMatrix en douceur

Les filtres CSS sont formidables mais ils présentent un inconvénient majeur : on ne peut pas manipuler les canaux. C’est ici qu'intervient feColorMatrix, une méthode SVG présentée par Una Kravets.

Par

Avez-vous remarqué la campagne de pub de Spotify à la fin de l’année dernière ? Un visuel très intéressant grâce à la manipulation de couleurs.

La manipulation d’images est une façon très efficace de faire ressortir un projet — ou simplement d’y ajouter une petite étincelle — et les filtres web offrent des possibilités dynamiques et en cascade pour les réaliser via les navigateurs.

CSS vs. SVG

J’ai lancé en début d’année CSSgram, une bibliothèque CSS qui utilise les filtres et les blend modes pour recréer les filtres Instagram.

Vous pouvez retrouver certains de ces filtres dans la série d’articles d’Una Kravets traduits dans La Cascade

On pourrait les réaliser avec un peu de bricolage et de blend modes, mais il manque une fonctionnalité essentielle aux filtres CSS : la manipulation par canal. C’est un inconvénient majeur. Les filtres sont très pratiques mais ce sont de simples raccourcis dérivés de SVG qui ne permettent pas de contrôler les canaux RGBA.

SVG, et en particulier feColorMatrix, nous permet grâce à un meilleur contrôle de passer au niveau supérieur de la manipulation des images et des effets spéciaux.

Les filtres SVG

Dans le monde de SVG, les effets de filtre sont préfixés avec fe- (pour filter effect). Ils permettent de produire toute une palettes d’effets de couleurs, de flous et de textures 3D. Le terme fe- est un peu vague, mais vous trouverez en fin d’article un résumé de chaque méthode.

Les filtres SVG sont actuellement supportés par les navigateurs suivants :

Capture d’écran de caniuse.com

Donc, oui, tout va bien pour l’essentiel, sauf si vous devez assurer une compatibilité avec IE9 ou plus ancien. La compatibilité des filtres SVG est assez stable et elle est plus répandue que celle des filtres CSS et des blend modes. Il y a moins de bugs bizarres comme cela peut être le cas des CSS blend modes (pour lesquels Chrome 46 a des problèmes de rendu des modes multiply, difference et exclusion).

N.B.: certains filtres 3D tels que feConvolveMatrix connaissent des bugs avec certains navigateurs, mais ce n’est pas le cas de feColorMatrix sur lequel nous nous concentrons dans cet article. Gardez à l’esprit qu’il y aura nécessairement un léger impact sur la performance, comme pour toute action exécutée via le navigateur (contrairement à une image pré-éditée).

Utiliser les filtres

Un filtre SVG se présente à peu près comme ceci :

<svg>  
  <filter id="filterName">
    // la définition du filtre ici peut
    // inclure plusieurs items
  </filter>
</svg>  

À l’intérieur d’un SVG, vous pouvez déclarer un filtre. Le plus souvent, on déclarera les filtres à l’intérieur de defs d’un SVG, auxquels on pourra appliquer des styles CSS :

//CSS
.filter-me {
  filter: url(’#filterName’);
}

L’URL du filtre est relative, donc filter: url(’../img/filter.svg#filterName’) et filter: url(’http://una.im/filters.svg#filterName’) sont toutes les deux valides.

feColorMatrix

Pour la manipulation de couleurs, feColorMatrix est votre meilleure option. feColorMatrix est un type de filtre qui utilise une matrice pour agir sur les valeurs de couleurs canal par canal (en RGBA). On peut rapprocher cela de l’editing des canaux dans Photoshop.

Voici à quoi ressemble feColorMatrix (avec une valeur de 1 pour chaque valeur RGBA dans l’image originale) :

<filter id="linear">  
    <feColorMatrix
      type="matrix"
      values="R 0 0 0 0
              0 G 0 0 0
              0 0 B 0 0
              0 0 0 A 0 "/>
  </filter>
</feColorMatrix>  

Ici, la matrice calcule une valeur RGBA dans chaque rangée, pour la donner à chaque canal RGBA. Le dernier nombre est un multiplicateur. La valeur RGBA finale peut être lue de haut en bas comme une colonne :

/* R G B A 1 */
1 0 0 0 0 // R = 1*R + 0*G + 0*B + 0*A + 0  
0 1 0 0 0 // G = 0*R + 1*G + 0*B + 0*A + 0  
0 0 1 0 0 // B = 0*R + 0*G + 1*B + 0*A + 0  
0 0 0 1 0 // A = 0*R + 0*G + 0*B + 1*A + 0  

Voici une meilleure visualisation :

Le tableau du milieu représente les valeurs par défaut (pas de modification), le tableau du bas représente une image colorée en vert : les canaux rouge et bleu sont à zéro, le canal alpha est inchangé, mais la teinte est à zéro.

Valeurs RGB

Colorisation
Vous pouvez colorer les images en omettant et en mélangeant les canaux de couleurs de la façon suivante :

<!-- ici, il manque les canaux B & G (seul R est à 1) -->  
<filter id="red">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   0   0   0
            0   0   0   1   0 "/>
</filter>

<!-- ici, il manque les canaux R & G (seul B est à 1) -->  
<filter id="blue">  
 <feColorMatrix
    type="matrix"
    values="0   0   0   0   0
            0   0   0   0   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>

<!-- ici, il manque les canaux R & B (seul G est à 1) -->  
<filter id="green">  
  <feColorMatrix
    type="matrix"
    values="0   0   0   0   0
            0   1   0   0   0
            0   0   0   0   0
            0   0   0   1   0 "/>
</filter>  

Et voici ce que donne l’ajout d’un filtre “vert” à une image :

Mixer les canaux
On peut également mélanger les canaux RGB pour obtenir des couleurs solides :

<!-- ici, il manque le canal B (mélange de R & G, rouge & vert)  
Rouge + Vert = Jaune  
Autrement dit, il n’y a pas de canal Jaune  
-->
<filter id="yellow">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   1   0   0   0
            0   0   0   0   0
            0   0   0   1   0 "/>
</filter>

<!-- ici, il manque le canal G (mélange de R & B, rouge & bleu)  
Red + Blue = Magenta  
-->
<filter id="magenta">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>

<!-- ici, il manque le canal R (mélange de G & B, vert & bleu)  
Green + Blue = Cyan  
-->
<filter id="cyan">  
  <feColorMatrix
    type="matrix"
    values="0   0   0   0   0
            0   1   0   0   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>  

Dans chacun des exemples ci-dessus, nous avons mélangé les couleurs en mode CMYK, autrement dit la suppression du canal rouge signifie qu’il ne reste que le vert et le bleu. Lorsque le vert et le bleu sont mélangés, ils créent du cyan. Le rouge et le bleu donnent du magenta. Nous conservons un peu des valeurs rouge et bleu lorsqu’elles sont dominantes, mais dans les parties où elles sont absentes (par exemple des surfaces lumineuses blanches où toutes les couleurs sont présentes dans le schéma RGB, ou dans des parties vertes), les valeurs RGBA des deux autres canaux les remplacent.

Justin McDowell a écrit un excellent article expliquant la théories des couleurs HSL (hue, saturation, lightness). Pour SVG, la valeur de lightness est la luminosité, que nous devons garder à l’esprit. Ici, chaque niveau de luminosité est conservé dans chaque canal, donc pour le filtre magenta nous obtenons quelque chose comme ça :

Pourquoi y a-t-il tant de magenta dans les nuages et dans les valeurs les plus lumineuses ? Considérons ce diagramme RGB :

Lorsqu’il manque une valeur, les deux autres prennent sa place. Par conséquent, lorsque le vert disparaît, il n’y a pas de blanc, ni de cyan, ni de jaune. Ces couleurs ne disparaissent pas en fait, parce que leur valeur de luminosité (ou valeur alpha) est restée inchangée. Voyons maintenant ce qui se passe si nous manipulons ces canaux alpha.

Valeurs alpha
Nous pouvons jouer avec les ombres et les lumières via les canaux alpha (la quatrième colonne). La quatrième rangée affecte les canaux dans leur ensemble, tandis que la quatrième colonne les affecte par canal.

<!-- Agit comme un filtre d’opacité, à .5 -->  
<filter id="alpha">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   1   0   0   0
            0   0   1   0   0
            0   0   0   .5  0 "/>
</filter>

<!-- augmente l’opacité du vert pour être au même niveau d’opacité que l’opacité globale -->  
<filter id="hard-green">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   1   0   1   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>

<filter id="hard-yellow">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   1   0
            0   1   0   1   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>  

Pour illustrer ceci, dans l’exemple qui suit nous réutilisons la matrice de l’exemple magenta et nous ajoutons un canal alpha à 100% sur le bleu. Nous conservons les valeurs rouges, mais nous écrasons le rouge dans les ombres, ce qui fait que les ombres deviennent toutes bleues tandis que les valeurs les plus lumineuses qui comportent du rouge deviennent un mélange de bleu et de rouge (magenta).

<filter id="blue-shadow-magenta-highlight">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   1   1   0
            0   0   0   1   0 "/>
</filter>  

Si cette valeur était inférieure à 1 (et jusqu’à -1) c’est l’inverse qui se produirait. Les ombres deviendraient rouge au lieu de bleu. À -1, les deux filtres suivants produisent le même effet :

<filter id="red-overlay">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   1  -1   0
            0   0   0   1   0 "/>
</filter>


<filter id="identical-red-overlay">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   0   0   0
            0   0   0   1   0 "/>
</filter>  

Si nous donnons une valeur de .5 au lieu de -1, nous pouvons voir le mélange de couleurs dans les ombres :

<filter id="blue-magenta-2">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   0   0   0   0
            0   0   1  .5   0
            0   0   0   1   0 "/>
</filter>  

Exploser les canaux
Nous pouvons affecter l’alpha global de canaux individuels via la quatrième rangée. Notre exemple comporte un ciel bleu, dont nous pouvons nous débarrasser — ainsi que des autres valeurs bleues — en convertissant les valeurs bleues en blanc de la manière suivante :

<filter id="elim-blue">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   1   0   0   0
            0   0   1   0   0
            0   0   -2   1   0 "/>
</filter>  

Voici quelques exemples supplémentaires de mélanges de canaux :

<!-- Pas de canal G, Rouge à 100% sur le canal G, celui-ci semblant rouge (luminosité du canal G perdue) -->  
<filter id="no-g-red">  
  <feColorMatrix
    type="matrix"
    values="1   1   0   0   0
            0   0   0   0   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>

<!-- Pas de canal G, Rouge et Vert à 100% sur le canal G, celui-ci semblant Magenta (luminosité du canal G perdue) -->  
<filter id="no-g-magenta">  
  <feColorMatrix
    type="matrix"
    values="1   1   0   0   0
            0   0   0   0   0
            0   1   1   0   0
            0   0   0   1   0 "/>
</filter>

<!-- Canal G partagé par les valeurs Rouge et Bleu. C’est un effet Magenta colorisé (luminosité maintenue) -->  
<filter id="yes-g-colorized-magenta">  
  <feColorMatrix
    type="matrix"
    values="1   1   0   0   0
            0   1   0   0   0
            0   1   1   0   0
            0   0   0   1   0 "/>
</filter>  

Éclaircir et obscurcir

Vous pouvez créer un effet obscurci en assignant aux valeurs RGB de chaque canal une valeur inférieure à 1 (qui est leur valeur naturelle). Pour éclaircir, donnez des valeurs supérieures à 1. On peut le voir comme un agrandissement du cercle de couleurs RGB que nous avons vu précédemment. Plus le rayon est large, plus les tons créés sont lumineux et plus le blanc est éclatant. L’inverse se produit quand le rayon diminue.

normal, éclairci, obscurci

Voici la matrice :

<filter id="darken">  
  <feColorMatrix
    type="matrix"
    values=".5   0   0   0   0
             0  .5   0   0   0
             0   0  .5   0   0
             0   0   0   1   0 "/>
</filter>  
<filter id="lighten">  
  <feColorMatrix
    type="matrix"
    values="1.5   0   0   0   0
            0   1.5   0   0   0
            0   0   1.5   0   0
            0   0   0   1   0 "/>
</filter>  

Échelles de gris
On peut créer un effet d’échelle de gris en ne prenant de valeurs que sur une colonne. Selon les niveaux auxquels ils sont appliqués, on obtient des effets de gris différents. Considérez ces exemples :

<filter id="gray-on-light">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            1   0   0   0   0
            1   0   0   0   0
            0   0   0   1   0 "/>
</filter>  
<filter id="gray-on-mid">  
  <feColorMatrix
    type="matrix"
    values="0   1   0   0   0
            0   1   0   0   0
            0   1   0   0   0
            0   0   0   1   0 "/>
</filter>  
<filter id="gray-on-dark">  
  <feColorMatrix
    type="matrix"
    values="0   0   1   0   0
            0   0   1   0   0
            0   0   1   0   0
            0   0   0   1   0 "/>
</filter>  

On met tout ensemble

La véritable puissance de feColorMatrix réside dans sa capacité à mélanger les canaux et à combiner les différents concepts pour créer de nouveaux effets visuels.

Pouvez-vous lire ce qui se passe dans ce filtre ?

<filter id="peachy">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0  .5   0   0   0
            0   0   0  .5   0
            0   0   0   1   0 "/>
</filter>  

Nous utilisons le canal rouge sur son canal alpha normal, nous appliquons le vert à demi-puissance, et nous appliquons le bleu sur les canaux alpha les plus sombres, mais pas à sa place normale (qui serait la troisième colonne). Cet effet nous donne du bleu sombre dans les ombres, et un mélange de red et de demi-vert pour les point lumineux ou intermédiaires. Si nous nous rappelons que rouge + vert = jaune, alors rouge + vert/2 devrait nous donner une couleur plus proche du corail :

Voici un autre exemple :

<filter id="lime">  
  <feColorMatrix
    type="matrix"
    values="1   0   0   0   0
            0   2   0   0   0
            0   0   0  .5   0
            0   0   0   1   0 "/>
</filter>  

Dans ce segment, nous utilisons la teinte normale de rouge, un vert éclatant et un bleu dépourvu de ses pixels de teinte mais appliqué aux ombres. À nouveau, nous voyons ce bleu sombre dans les ombres, et puisque
rouge + vert = jaune, alors rouge + vert*2 devrait être proche d’un jaune-vert dans les parties les plus claires :

On peut partir dans de belles aventures en jouant avec ces valeurs. Un excellent exemple de ces explorations est le Dev Tools Challenger de Rachel Nabor, dans lequel elle filtre les longueurs d’ondes les plus longues (c’est à dire les canaux rouge et orange) de poissons dans la mer, et explique ainsi pourquoi l’hoplostète orange (“Orange Roughy”) apparaît noir au fond de l’eau (Remarque : vous aurez besoin de Firefox).

Cool ! Un peu de science, des filtres, et maintenant que vous avez une maîtrise basique de ce qui se passe, vous avez vous aussi les outils vous permettant de créer de nouveaux effets.

Pour obtenir quelques effets bien radicaux comme les duotones de Spotify, je vous recommande la lecture de l’article d’Amelia Bellamy-Royds, qui explore les détails de feColorMatrix. Sara Soueidan a également écrit un excellent article sur les effets d’images dans lequel elle recrée les CSS blend modes avec SVG.

Quelques références d’effets de filtres

Une fois bien compris ce qui se passe avec feColorMatrix, vous êtes prêt à créer des filtres détaillés à l’intérieur d’une définition de filtre, mais il existe bien d’autres options qui vous permettront d’aller encore plus loin. Voici un guide pratique de toutes les options fe-* actuellement disponibles :

  • feBlend : similaire aux CSS blend modes, cette fonction décrit la façon dont les images interagissent via un blend mode.
  • feComponentTransfer : un terme parapluie pour une fonction qui altère les canaux RGBA individuels (p.ex. feFuncG).
  • feComposite: une primitive de filtre qui définit les interactions d’images au niveau des pixels.
  • feConvolveMatrix: ce filtre conduit la façon dont les pixels interagissent avec leurs voisins (p.ex. en floutant ou en améliorant la netteté)
  • feDiffuseLighting : définit une source de lumière.
  • feDisplacementMap: déplace une image (in) en utilisant les valeurs de pixels d’un autre input (in2).
  • feGaussianBlur: floute les pixels en input en utilisant une déviation standard.
  • feImage : utilisé à l’intérieur d’autres filtres (comme feBlend ou feComposite)
  • feMerge : permet l’application asynchrone d’effets de filtrage.
  • feMorphology : réduit ou dilate les lignes d’une source graphique (p.ex. les traits d’un texte).
  • feOffset: utilisé pour créer des ombres portées.
  • feTile: renvoie à la façon dont une image est répétée pour remplir un espace.
  • feTurbulence: permet la création de textures synthétiques via Perlin Noise.

Ressources complémentaires :


Intéressé par SVG ? Retrouvez une liste des meilleurs articles et ressources du web.

Tous les articles sur SVG parus dans la Cascade.

Tous les articles sur les couleurs parus dans la Cascade.

Du même auteur, dans la Cascade :

  1. Effet vintage délavé
  2. Effet lunettes 3D
  3. Trois sortes de vignettes
  4. Textures Bokeh
  5. Filtres lomographiques
  6. Effet photo infrarouge

Sur les Couleurs

Articles sur les mêmes thèmes dans la Cascade :

Ressources complémentaires en français

Ressources complémentaires en anglais

Outils

  • Color Template, pour tout savoir sur les couleurs, un très joli site, très complet et instructif.
  • Adobe Kuler, outil en ligne pour choisir ses couleurs, très complet et inspirant.
  • Color Scheme Designer, comme Kuler, avec un fonctionnement différent, très bien fait.
  • WebColorData, avec cet outil les couleurs n’auront plus aucun secret pour vous. Entrez l’url d’un site internet et WebColorData référence en un panel les couleurs dominantes trouvées. Vraiment pratique.
  • Color.io, autre outil très pratique pour choisir une couleur et toute la palette complémentaire.
  • Pictaculous, quel schéma de couleurs utiliser avec une image ? Uploadez votre image sur Pictaculous, il vous donnera une belle palette de couleurs.
  • Mudcube colour sphere vous permet de créer des schémas de couleurs et de vérifier leur accessibilité aux personnes souffrant de déficiences visuelles.
  • 0 to 255, un outil simple pour trouver des variations sur une couleur.
  • Hex.colorrrs, un convertisseur de Hex en RGB, simple, bien fait, visualisation de la couleur en cours de frappe.
  • Brand Colors, une collection de palettes de couleurs des grandes marques.
  • The colors of motion, un site créatif par Charlie Clark qui explore l’utilisation des couleurs dans les films. Pas de mots, juste des couleurs. Choisissez un film, cliquez sur une bande de couleur, regardez les images et l’harmonie des couleurs.
  • Spectrum, une superbe application (Mac) pour créer vos palettes, les triturer, les exporter, intégrer directement une couleur dans CSS, etc.


Article original paru le 11 février 2016 dans A List Apart.

Sur l’auteur : est développeur front-end, elle conçoit des systèmes de design et des prototypes de logiciels chez IBM Design à Austin, Texas. Elle fait partie des membres principaux de l’organisation Design Open et elle est fondatrice des meetups Sassy DC et ATX Sass. Elle dessine parfois, elle code beaucoup et parle de Sass, de performance web et d’open source. On peut la suivre sur Twitter, Dribbble, Github, Codepen.

Traduit avec l’aimable autorisation de A List Apart et de l’auteur.
Copyright A List Apart © 2016.