XSL/XHTML+SVG

Comment intégrer une image SVG dans un document (X)HTML statique ou dynamique ?

Intérêt du SVG

L'utilisation en lieu et place d'images classiques (jpeg, png, etc.) permet une certaine souplesse dans certains cas.

Tout d'abord, étant vectoriel, il est souvent plus compact qu'un autre format. De plus, il permet un usage avancé des CSS puisqu'on peut lui attribuer des propriétés sans utiliser plusieurs images. Les images et icônes peuvent donc s'adapter facilement à une page sans avoir besoin de les retoucher.

Cas statique

L'insertion de SVG dans un document statique peut se faire de différentes façons, en fonction du format du document support.

Insertion du SVG dans le document

L'insertion du SVG directement dans le document permet d'éviter certains allers-retours entre le client et le serveur et de gagner du temps de chargement. Cela est utile lorsque l'image n'est utilisée qu'une seule fois.

Lorsque l'image est utilisée plusieurs fois, il vaut mieux l'inclure dans un fichier à part puis l'appeler depuis le document. L'image ne sera chargée qu'une seule fois pour toutes (sauf si elle est modifiée entre temps).

HTML + SVG

Le HTML est un format particulier, ou plutôt traité de façon particulière et optimalisée par les navigateurs. Pour cette raison, ces derniers effectuent un certain nombre de raccourcis implicites (le document peut être mal formé sans provoquer d'erreur d'affichage) et quelques limitations. Arriver au résultat escompté nécessite quelques adaptations.

Dans le cas de l'inclusion dans un document HTML, il faut appeler le SVG systématiquement par son espace de nom à la racine du bloc SVG :

<a href="#top">
<div class="icon">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="32" height="32" viewBox="0 0 32 32" xml:space="preserve">
<polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="16,2 30,2 30,16"/>
<polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="2,16 2,30 16,30"/>
</svg>
</div>
</a>

Et cela à chaque fois que vous utiliserez un bloc de code <svg>…</svg>.

XHTML + SVG

Dans le cas du XHTML, le navigateur n'effectue pas les raccourcis habituels pour un affichage plus rapide. Il prend le temps d'exécuter à la lettre les directives XML qui lui sont indiquées (à tel point qu'un document mal formé ne sera pas affiché du tout). Il convient donc de valider le document avant de l'utiliser en production.

Le cas du XHTML est à la fois plus simple et plus propre. Il utilise la puissance du XML, à savoir les espaces de nom. Le SVG sera utilisé sur un espace de nom différent que celui du XHTML. Cela permet un certain nombre de factorisations.

Même s'il peut être défini à chaque appel, il est plus simple de l'appeler une seule fois à la racine du document :

<html…
xmlns:svg="http://www.w3.org/2000/svg"

>
[document XHTML]

</html>

Puis d'utiliser le SVG dans son espace de nom défini (svg:) :

<a href="#top">
<div class="icon">
<svg:svg version="1.1" width="32" height="32" viewBox="0 0 32 32" xml:space="preserve">
<svg:polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="16,2 30,2 30,16"/>
<svg:polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="2,16 2,30 16,30"/>
</svg:svg>
</div>
</a>

SVG externe au document

Dans la plupart des cas, l'utilisation d'une image SVG ne se limite pas à un usage unique. Il s'agit, par exemple, d'icônes. Dans ce cas, il peut être utile et plus performant d'utiliser des fichiers SVG externes au document et de les appeler depuis le document support.

Cas standard d'appel

Le cas le plus standard d'appel est identique à n'importe quel appel d'image grâce à l'élément img :

<img src="/chemin/vers/mon_fichier.svg"/>

Ce cas ne représente pas vraiment d'intérêt et de difficulté. On ne peut pas styler l'image avec du CSS. Pour le faire, il faut utiliser d'autres méthodes d'appel.

Cas avancé d'appel

Imaginez que vous ayez un jeu d'icônes à utiliser. Plutôt que d'appeler chaque icône une à une et faire autant de requêtes HTTP qu'il y a d'icônes, il sera plus performant de les régrouper dans un seul fichier externe et de les appeler ensuite.

Le XML se prête bien à ce genre de cas de figure.

Pour cela, il faut d'abord rassembler toutes les icônes SVG dans un seul fichier (ce qu'on appelle un sprite), chaque icône étant encapsulé dans un élément symbol associé à un id :

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">

<symbol id="icon1" width="32" height="32" viewBox="0 0 32 32" xml:space="preserve">
<polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="16,2 30,2 30,16"/>
<polyline fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="2,16 2,30 16,30"/>
</symbol>

<symbol id="icon2" width="32" height="32" viewBox="0 0 32 32" xml:space="preserve">

</symbol> …

</svg>

Attention

Cet id est obligatoire pour pouvoir utiliser l'icône par la suite.

Il ne reste ensuite plus qu'à utiliser l'icône dans le document support de la façon suivante, grâce à l'élément use, soit :

<a href="#top">
<div class="icon">
<svg xmlns="http://www.w3.org/2000/svg">
<use xlink:href="sprite1.svg#icon1"></use>
</svg>
</div>
</a>

dans le cas du HTML, soit 

<a href="#top">
<div class="icon">
<svg:svg>
<svg:use xlink:href="sprite1.svg#icon1"></svg:use>
</svg:svg>
</div>
</a>

dans le cas XHTML.

Attention

Attention à bien définir l'espace de nom xlink pour utiliser xlink:href :

xmlns:xlink="http://www.w3.org/1999/xlink"

CSS

Dans les deux cas, l'usage du CSS est identique et s'applique comme sur n'importe quel élément (X)HTML standard :

.icon:hover polyline,
.icon:focus polyline {
stroke-width: 4;
}

.icon:hover rect,
.icon:focus rect {
stroke-width: 2;
}

.icon:active rect {
stroke-width: 6;
transition: all 100ms ease-in-out;
}

.icon:active polyline {
stroke-width: 6;
transition: all 100ms ease-in-out;
}

polyline, rect {
transition: all 250ms ease-in-out;
}

Astuce

En règle générale, pour mieux styler les éléments SVG, il convient de retirer dans le code source tous les éléments de couleur (fill, etc.) et de les définir dans le CSS.

Cas dynamique

XSL/XHTML+SVG : le SVG dynamique

modèles

Maintenant que le SVG peut directement être intégré dans une page XHTML pour l'affichage, rien n'empêche de générer cette page dynamiquement, y compris le SVG, grâce à une feuille de style (XSL) :

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="http://www.w3.org/2000/svg">

<xsl:output
method="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
indent="yes"
encoding="iso-8859-1"/>


<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<title>Un exemple de SVG dynamique</title>
<link rel="stylesheet" type="text/css" href="moncss.css"/>
<meta content="application/xhtml+xml; charset=iutf-8" http-equiv="content-type"/>
</head>

<body>

<h1>Un exemple de SVG dynamique</h1>

<svg:svg width="1200px" height="1000px" viewbox="0 0 1200 1000">
<!-- insérez votre code ici -->

</svg:svg>
</body>
</html>
</xsl:template>

<!-- insérez les autres templates ici -->

</xsl:stylesheet>

Il ne reste plus qu'à compléter avec le code xhtml, svg, et xsl…

Il suffira ensuite de créer le fichier XML qui va bien, faisant appel à cette feuille de style pour voir s'afficher une belle image.

Remarque

Dans les exemples présentés, le SVG inséré a une taille fixe et définie à l'avance.

<svg width="1200px" height="1000px"…

Cependant, il peut être parfois nécessaire de paramétrer la taille de l'image et en la récupérant par une variable (locale ou globales). Dans ce cas, cette notation ne fonctionne pas car le xmlns="http://www.w3.org/2000/svg" va provoquer une erreur. Il faut déplacer cette définition dans <xsl:stylesheet…, mais dans ce cas, chaque élément SVG sera précédé de svg: :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="http://www.w3.org/2000/svg">
<svg:svg width="$width" height="$height" viewbox="0 0 1200 1000" >

Et l'on peut supprimer les xmlns de la balise svg.

voir un exemple ici.

Exemple

Nous voulons insérer l'image dynamique suivante :

Un exemple d'étiquette Ademe consommation Un exemple d'étiquette Ademe émission

Il s'agit d'une image reproduire des étiquettes de classe Ademe concernant la consommation ou l'émission.

Cette image est définie dynamiquement par un XSLT qui prend en paramètre la dimension de l'image ainsi que la valeur de la mesure (A, B, C…).

Valeur :

Consommation

Emission