svg : les bases

Les images au format SVG (Scalable Vector Graphics) sont vectorisées, contrairement aux images au format JPG ou PNG par exemple. Qu’est-ce que ça implique ?

  • on peut donner la dimension qu’on veut à une image SVG sans perte de qualité
  • le format est basé sur XLM, donc lisible et facilement modifiable, il est aussi peu encombrant
  • on peut ajouter du style CSS
  • on peut créer des animations de plusieurs façons

On se rend compte que ce format est vraiment intéressant, alors pourquoi est-il si peu utilisé sur le WEB ?

En fait le format était plutôt mal supporté par les navigateurs mais ce n’est plus le cas, il suffit de regarder sur le site CanI use :

Il n’y a donc plus aucune raison valable pour ne pas utiliser ce format dans les sites web. Alors je vous propose de découvrir ce format et la façon d’intégrer ce type d’image dans une page HTML ou même, pourquoi pas, de l’utiliser comme base d’une application.

Ça ressemble à quoi un fichier SVG ?

Dans le HTML 5 il existe une balise <svg>, on peut donc intégrer directement le code du fichier SVG dans une page HTML. Voilà dans sa plus simple expression :

<!DOCTYPE html>
<html lang="fr">
<body>
    <svg height="100" width="100">
        <circle cx="50" cy="50" r="40" stroke="blue" stroke-width="3" fill="green" />
    </svg> 
</body>
</html>

On trouve dans la balise svg les dimensions de l’image exprimées en pixels (mais toutes les unités sont utilisables).

On a ensuite une balise circle avec des propriétés pour le positionnement, la dimension du trait, les couleurs…

On se rend compte que la syntaxe est simple et lisible et aisément modifiable même dans un éditeur de texte sommaire.

On peut également mettre le code SVG dans un fichier séparé. Donc dans le fichier on aura juste :

<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="blue" stroke-width="3" fill="green" />
</svg>

Si vous ouvrez ce fichier à partir d’un navigateur vous verrez le cercle parce que votre navigateur sait interpréter les fichiers XML.

On verra plus tard les façons d’appeler ce fichier à partir du code HTML, parce qu’il y a plusieurs façons de faire et qu’il est un peu délicat de choisir… Pour le moment on va se focaliser sur le format des fichiers SVG.

Les formes de base

On a vu ci-dessus qu’on peut dessiner un cercle facilement en fixant ses paramètres : position du centre, rayon… avec des attributs.

On peut de la même manière dessiner un rectangle :

<rect x="20" y="20" width="200" height="100" stroke="red" stroke-width="6" fill="#ff0" />

On définit :

  • la position en x (l’origine est situé en haut à gauche, par défaut on a des pixels)
  • la position en y
  • la largeur
  • la hauteur
  • l’épaisseur et la couleur du trait
  • la couleur de remplissage

On peut aussi dessiner une ligne :

<line x1="150" y1="50" x2="100" y2="200" stroke="blue"  />

On définit les coordonnées du point de départ et du point d’arrivée.

On a aussi la polyligne :

<polyline points="10,20 30,5 65,100 40,100 110,20 200,150" stroke="blue" stroke-width="5" fill="none" />

Là on définit tous les points. remarquez que j’ai précisé aucun remplissage (fill= »none »), sinon on aurait eu ce résultat :

Par défaut on a le remplissage et la couleur aussi par défaut est le noir.

La syntaxe pour un polygone est très proche :

<polygon points="10,20 80,50 65,100" stroke="blue" stroke-width="4" fill="red" />

Pour une ellipse c’est la même syntaxe que pour un cercle mais en précisant les deux rayons :

<ellipse cx="100" cy="100" rx="60" ry="40" stroke="purple" stroke-width="3" fill="blue" />

Donc il est facile de dessiner à partir de ces bases.

Vous pouvez trouver une bonne description avec des exemples des formes de base sur w3school.

Répétition

Supposez qu’on ait besoin de 3 carrés identiques mis à part leur couleur :

Avec les éléments vus ci-dessus le code devient :

<rect x="20" y="20" width="50" height="50" stroke="red" fill="red" />
<rect x="90" y="20" width="50" height="50" stroke="blue" fill="blue" />
<rect x="160" y="20" width="50" height="50" stroke="yellow" fill="yellow" />

On se rend compte qu’il y a des répétitions pas très heureuses…

On dispose de la balise defs pour définir une forme sans la tracer et ensuite l’utiliser :

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="150" width="400">
    <defs>
        <rect id="carre" y="20" width="50" height="50" />
    </defs>
    <use xlink:href="#carre" x="20" stroke="red" fill="red" />
    <use xlink:href="#carre" x="90" stroke="blue" fill="blue" />
    <use xlink:href="#carre" x="160" stroke="yellow" fill="yellow" />
</svg>

L’attribut xlink:href définit un deuxième espace de noms XML. On ne peut pas encore utiliser simplement href parce que ça fait partie de SVG 2 qui est loin d’être pris en charge par tous les navigateurs.

Dans la balise defs on peut placer toutes les définitions et les repérer par un identifiant.

Groupement

Une autre possibilité du SVG qui est très utilisée est le fait de pouvoir grouper des éléments. Quel intérêt ? Tout simplement ça permet d’avoir une structure plus claire et de par exemple appliquer des styles communs.

<g stroke="magenta" stroke-width="5">
    <rect x="20" y="20" width="50" height="50" fill="red" /> 
    <rect x="90" y="20" width="50" height="50" fill="blue" /> 
    <rect x="160" y="20" width="50" height="50" fill="yellow" />
</g>

On peut évidemment grouper et éviter les répétitions avec une définition :

<defs> 
    <rect id="carre" y="20" width="50" height="50" /> 
</defs>
<g stroke="magenta" stroke-width="5">
    <use xlink:href="#carre" x="20" fill="red" />
    <use xlink:href="#carre" x="90" fill="blue" />
    <use xlink:href="#carre" x="160" fill="yellow" />
</g>

Le style

On a vu qu’on définit l’apparence avec des attributs mais on peut aussi utiliser du style CSS. Si on reprend cet exemple vu ci-dessus :

<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="3" fill="green" />

On peut le réécrire ainsi avec des règles de style en ligne :

<circle cx="50" cy="50" r="40" style="fill:green;stroke:blue;stroke-width:3" />

Ou de façon plus classique :

<style type="text/css">
    circle {            
        stroke: blue;
        stroke-width: 3;
    }
    .green {
        fill: green;
    }
</style>
<circle class="green" cx="50" cy="50" r="40" />

Du dégradé

Pour le moment on a vu des fond unis, mais on peut aussi utiliser des dégradés. La syntaxe n’est pas des plus évidentes alors il est bien plus pratique de passer par un générateur ! En général ceux qui savent générer des dégradés pour le CSS savent aussi le faire pour le SVG, par exemple celui d’Angrytools :

Voici un dégradé linéaire créé en quelques clics :

<defs>
    <linearGradient id="lgrad" x1="84%" y1="0%" x2="16%" y2="100%" >
        <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
        <stop offset="25%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
        <stop offset="56%" style="stop-color:rgb(164,214,159);stop-opacity:1" />
        <stop offset="100%" style="stop-color:rgb(0,255,255);stop-opacity:1" />
    </linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#lgrad)"/>

On peut aussi créer des dégradés radiaux :

Le texte

On peut dessiner mais on peut aussi écrire avec la balise text :

<text x="20" y="20" fill="red">Je sais écrire !</text>

On dispose de toutes les règles CSS pour styliser le texte, par exemple :

<style>
    text {
        color: blue;
        text-transform: uppercase;
        font-size: 30px;
        text-shadow: 3px 2px darkblue;
    }
</style>
<text x="20" y="30">Je sais écrire !</text>

Les animations

la partie intéressante quand on utilise SVG est l’animation. Dans la spécification SVG on trouve une belle partie qui concerne l’animation : SMIL (Synchronized Multimedia Integration Language). Mais IE ne supporte pas cette spécification et du coup elle est très peu utilisée !

Mais on peut quand même utiliser les animations CSS !

Voici un exemple simple :

<style>
    @keyframes couleurs {
        from {fill: red;}
        to {fill: yellow;}
    }
    ellipse {
        animation-name: couleurs;
        animation-duration: 4s;
    }
</style>
<ellipse cx="200" cy="80" rx="100" ry="50"  style="fill:red;stroke:purple;stroke-width:10" />

La couleur de fond passe progressivement de rouge :

A jaune :

Utiliser un outil graphique

Tant qu’on s’en tient à des formes simples il est envisageable de coder directement mais quand ça devient plus complexe on a intérêt à passer par un outil graphique. Le meilleur pour moi est Inkscape : puissant, bien documenté et gratuit. Voici par exemple un carré avec des poids réalisé en quelques secondes :

Inkscape est directement au format SVG, il n’y a donc qu’à enregistrer et ouvrir dans un navigateur :

Le fichier résultant fait 8492 octets. Lorsqu’on regarde le code il n’apparaît pas forcément très efficace, par exemple ici il y a une longue répétition pour les cercles, en voici un extrait :

...
<circle
    id="circle5747"
    r="0.45"
    cy="6.186"
    cx="9.688"
    style="fill:black;stroke:none" />
<circle
    id="circle5749"
    r="0.45"
    cy="6.296"
    cx="3.379"
    style="fill:black;stroke:none" />
...

Un façon simple d’alléger le fichier est de faire la sauvegarde en SVG simple au lieu de la valeur par défaut SVG inkscape. Je tombe direct à 7454 octets avec l’élimination de métadonnées inutiles. On a aussi la commande Fichier->Nettoyer le document mais dans mon cas il n’y a rien à nettoyer parce qu’il est trop simple.

Vous pouvez également diminuer la précision numérique (Édition->Préférences->Sortie SVG) :

On peut considérer que 8 décimale est excessif donc diminuer cette valeur. Mais ne vous attendez pas à des miracles !

Il existe aussi des optimiseurs en ligne comme SVG Optimiser. On peut faire des réglages et constater le résultat en temps réel :

On voit qu’on peut gagner pas mal d’octets, là j’ai juste un déplacement des poids mais ce n’est pas important, le fichier tombe quand même à 2,4 Ko !

Mais évidemment le code devient illisible :

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105.8 105.8" height="400" width="400" version="1"><style>.a{fill:black;}</style><defs><pattern patternUnits="userSpaceOnUse" width="10" height="10" patternTransform="translate(0,0) scale(10,10)"><circle cx="2.6" cy="0.8" r="0.5" class="a"/><circle cx="3" cy="2.3" r="0.5" class="a"/><circle cx="4.4" cy="2.4" r="0.5" class="a"/><circle cx="1.8" cy="3" r="0.5" class="a"/><circle cx="6.1" cy="1.4" r="0.5" class="a"/><circle cx="5.8" cy="4.4" r="0.5" class="a"/><circle cx="4.3" cy="4" r="0.5" class="a"/><circle cx="5.5" cy="3" r="0.5" class="a"/><circle cx="4.8" cy="5.5" r="0.5" class="a"/><circle cx="2.7" cy="5.2" r="0.5" class="a"/><circle cx="8" cy="1.4" r="0.5" class="a"/><circle cx="7" cy="5" r="0.5" class="a"/><circle cx="4.3" cy="0.9" r="0.5" class="a"/><circle cx="7.1" cy="0.3" r="0.5" class="a"/><circle cx="9.6" cy="1" r="0.5" class="a"/><circle cx="7" cy="2.7" r="0.5" class="a"/><circle cx="8.9" cy="2.7" r="0.5" class="a"/><circle cx="9.3" cy="4.4" r="0.5" class="a"/><circle cx="7.8" cy="3.9" r="0.5" class="a"/><circle cx="8.3" cy="5.9" r="0.5" class="a"/><circle cx="8" cy="7.4" r="0.5" class="a"/><circle cx="9.3" cy="8.1" r="0.5" class="a"/><circle cx="8.2" cy="9.3" r="0.5" class="a"/><circle cx="9.7" cy="9.5" r="0.5" class="a"/><circle cx="9.7" cy="6.2" r="0.5" class="a"/><circle cx="3.4" cy="6.3" r="0.5" class="a"/><circle cx="2.9" cy="8.2" r="0.5" class="a"/><circle cx="4.6" cy="8.7" r="0.5" class="a"/><circle cx="3.2" cy="9.7" r="0.5" class="a"/><circle cx="5.7" cy="7.3" r="0.5" class="a"/><circle cx="6.7" cy="6.5" r="0.5" class="a"/><circle cx="5.7" cy="9.7" r="0.5" class="a"/><circle cx="6.5" cy="8.4" r="0.5" class="a"/><circle cx="4.4" cy="7.2" r="0.5" class="a"/><circle cx="0.6" cy="7.3" r="0.5" class="a"/><circle cx="0.8" cy="5.7" r="0.5" class="a"/><circle cx="1.3" cy="8.5" r="0.5" class="a"/><circle cx="2" cy="6.9" r="0.5" class="a"/><circle cx="0.4" cy="3.2" r="0.5" class="a"/><circle cx="1.2" cy="1.7" r="0.5" class="a"/><circle cx="1.2" cy="0.1" r="0.5" class="a"/><circle cx="1.2" cy="10.1" r="0.5" class="a"/><circle cx="1.3" cy="4.5" r="0.5" class="a"/><circle cx="3" cy="3.8" r="0.5" class="a"/></pattern></defs><metadata/><rect rx="0" ry="20.4" y="10.6" x="9.7" height="58.2" width="53.8" style="fill:url(#Polkadots-large);stroke-width:3;stroke:#8b0000"/></svg>

Vous pouvez trouver de nombreux optimiseurs de ce genre en ligne.

Vous pouvez aussi opter pour un outil basé sur node.js comme SVGO. Si vous n’aimez pas la console pas de souci il existe un GUI en ligne plutôt bien fait :

J’arrive à obtenir un fichier de 2,4 Ko avec un résultat cette fois identique avec un code très propre :

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105.833 105.833" height="400" width="400">
  <defs>
    <pattern patternUnits="userSpaceOnUse" width="10" height="10" patternTransform="scale(10)" id="a">
      <circle cx="2.567" cy=".81" r=".45"/>
      <circle cx="3.048" cy="2.33" r=".45"/>
      <circle cx="4.418" cy="2.415" r=".45"/>
      <circle cx="1.844" cy="3.029" r=".45"/>

      ...

      <circle cx="1.151" cy="10.093" r=".45"/>
      <circle cx="1.302" cy="4.451" r=".45"/>
      <circle cx="3.047" cy="3.763" r=".45"/>
    </pattern>
  </defs>
  <rect rx="0" ry="20.438" y="201.75" x="9.742" height="58.196" width="53.758" fill="url(#a)" stroke="#8b0000" stroke-width="2.646" transform="translate(0 -191.167)"/>
</svg>

C’est vraiment pour moi l’outil à privilégier.

Les banques d’images

Il existe de nombreuse banques de fichiers SVG dont pas mal de gratuits :

De quoi trouver ce qu’on cherche !

J’ai ainsi trouvé un superbe hibou :

Voici le code après optimisation :

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.219 512.219">
  <ellipse cx="256" cy="268.109" rx="255.781" ry="232" fill="#7e5c62"/>
  <path d="M302.719 351.445l-40.219-56a8.007 8.007 0 0 0-6.5-3.336h-.023a8.007 8.007 0 0 0-6.5 3.367l-39.781 56a7.995 7.995 0 0 0-.469 8.516l40 72a7.995 7.995 0 0 0 13.984 0l40-72a7.987 7.987 0 0 0-.492-8.547z" fill="#ffcd00"/>
  <path d="M249.476 295.477l-39.781 56a7.995 7.995 0 0 0-.469 8.516l40 72c1.37 2.474 3.954 4.009 6.773 4.088V292.109h-.023a8.005 8.005 0 0 0-6.5 3.368z" fill="#ff9100"/>
  <path d="M376.004 157.221c-53.829-7.459-101.497 23.404-119.894 69.182-18.398-45.779-66.066-76.642-119.896-69.182-49.922 6.919-89.733 48.001-95.284 98.093-7.489 67.585 45.219 124.795 111.289 124.795 41.549 0 77.757-22.652 97.077-56.259 2.989-5.2 10.639-5.2 13.628 0 19.32 33.607 55.527 56.259 97.076 56.259 66.07 0 118.779-57.211 111.289-124.796-5.552-50.092-45.363-91.174-95.285-98.092z" fill="#e6be94"/>
  <circle cx="360" cy="268.109" r="72" fill="#996459"/>
  <circle cx="152" cy="268.109" r="72" fill="#996459"/>
  <path d="M400 76.109h40c30.875 0 56-25.125 56-56 0-4.422 3.578-8 8-8s8 3.578 8 8v96c0 39.703-32.297 72-72 72h-96c-44.109 0-80 35.891-80 80 0 4.422-3.578 8-8 8s-8-3.578-8-8v-40c0-83.812 68.187-152 152-152z" fill="#996459"/>
  <path d="M112.219 76.109h-40c-30.875 0-56-25.125-56-56 0-4.422-3.578-8-8-8s-8 3.578-8 8v96c0 39.703 32.297 72 72 72h96c44.109 0 80 35.891 80 80 0 4.422 3.578 8 8 8s8-3.578 8-8v-40c0-83.812-68.188-152-152-152z" fill="#996459"/>
  <circle cx="152.219" cy="268.109" r="48" fill="#ffcd00"/>
  <circle cx="152.219" cy="268.109" r="24" fill="#5c546a"/>
  <circle cx="168.11" cy="252.219" r="16" fill="#fff"/>
  <circle cx="360" cy="268.109" r="48" fill="#ffcd00"/>
  <circle cx="360" cy="268.109" r="24" fill="#5c546a"/>
  <circle cx="375.89" cy="252.219" r="16" fill="#fff"/>
  <path d="M504.219 12.109c-4.422 0-8 3.578-8 8 0 30.875-25.125 56-56 56h-40c-67.028 0-123.954 43.663-144.109 103.999C235.954 119.772 179.028 76.109 112 76.109H72c-30.875 0-56-25.125-56-56 0-4.422-3.578-8-8-8s-8 3.578-8 8v48c0 30.928 25.072 56 56 56h56c54.303 0 101.859 28.707 128.675 71.684 3.288 5.27 9.202 8.316 15.413 8.316h.043c6.211 0 12.125-3.046 15.413-8.316 26.816-42.977 74.372-71.684 128.675-71.684h56c30.928 0 56-25.072 56-56v-48c0-4.422-3.579-8-8-8z" fill="#e6be94"/>
</svg>

Juste 2.3 Ko pour une image parfaitement redimensionnable sans perte de qualité !

Les librairies

Il existe aussi des librairies Javascript pour simplifier l’utilisation du SVG. La plus connue et utilisée est certainement Snapsvg. On dispose avec cette librairie d’une API très complète particulièrement intéressante pour l’animation. Voici un exemple simple d’utilisation :

<!DOCTYPE html>
<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
    <script>
        var s = Snap(800, 600)
        var r = s.rect(100,100,100,100,20,20).attr({ stroke: '#123456', 'strokeWidth': 20, fill: 'red', 'opacity': 0.7   });
    </script>
</body>
</html>

Je reviendrai en détail sur cette superbe librairie.

Une alternative intéressante est SVG.js. Plus légère mais moins bien documentée.

Conclusion

J’ai fait un petit tour d’horizon du SVG en montrant la structure des fichiers, la syntaxe de base et les outils et librairies disponibles. dans les prochains articles on ira plus loin dans la mise en œuvre.

Laisser un commentaire