Injecter du SVG directement dans du HTML 5

J’ai commencé à bidouiller une petite lib JavaScript capable de générer des charts en SVG (graphiques statistiques). Générer les graphiques en SVG n’est pas très dur, il suffit de quelques calculs mathématiques. En revanche ce qui m’a posé problème, c’est injecter le SVG dans la page HTML depuis le JavaScript. Je me suis alors penché sur l’intégration de SVG dans du HTML 5.

Images SVG

Afficher des images SVG externes est plutôt facile, il suffit d’utiliser la balise <object> ou la balise <iframe> , comme ceci :

<object type="image/svg+xml" data="chart.svg" width="120" height="40">
  <p>Votre navigateur ne supporte pas le SVG.</p>
</object>

SVG dans du XHTML

En revanche injecter du SVG directement dans le HTML est un peu plus sport. Historiquement il faut passer en XHTML et servir ses pages en utilisant le mimetype associé : application/xhtml+xml. Passant sur un format XML il est possible d’insérer du XML dans du XML. Dans notre cas : du SVG dans du XHTML (ça marche aussi pour du MathML).

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:svg="http://www.w3.org/2000/svg">
<body>
  <svg xmlns="http://www.w3.org/2000/svg" width="120" height="40">
    <rect x="10" y="10" width="100" height="20" style="fill:#000"/>
  </svg>
</body>
</html>

La contrepartie de cette technique c’est qu’il faut que les pages soient bien formées. Le moindre bug XML et l’affichage se réduit à une erreur de parsing. Outch.

SVG dans du HTML 5

Heureusement j’ai découvert il y a quelques jours une technique (presque) valide en HTML 5 et qui marche sur tous les navigateurs supportant le SVG. L’astuce consiste à déclarer la doctype HTML 5 tout en spécifiant les espaces de noms XHTML et SVG sur les balises html et svg, au besoin :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
  <svg xmlns="http://www.w3.org/2000/svg" width="120" height="40">
    <rect x="10" y="10" width="100" height="20" style="fill:#000"/>
  </svg>
</body>
</html>

Le SVG s’affiche alors correctement, et l’affichage de la page ne plante plus à la moindre erreur de parsing. Glop.

À noter cependant que pour être valide et conforme HTML 5, il faut alors servir ses pages avec le prologue XML <?xml version="1.0"?>, ainsi qu’avec le mimetype application/xhtml+xml. Le problème c’est que nos pages vont à nouveau être du XML et plus du HTML. C’est donc à vous de choisir : être valide et risquer des erreurs de parsing ; ou ne pas être valide.

Générer du SVG depuis JavaScript

Cette dernière technique est la seule qui soit aisée à utiliser lorsqu’on souhaite scripter la création du SVG (en JavaScript par ex) :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
  <script type="text/javascript">
  svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  svg.setAttribute('width', 120);
  svg.setAttribute('height', 40);
  document.body.appendChild(svg);
  </script>
</body>
</html>

Pour générer ensuite des éléments à ajouter à notre objet svg, il faut utiliser document.createElementNS. Ensuite c’est de la DOM bien classique (et c’est ça qui est génial avec SVG). Par exemple :

var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('x', 10);
rect.setAttribute('y', 10);
rect.setAttribute('width', 200);
rect.setAttribute('height', 20);
svg.appendChild(rect);

Autre solution :

Au départ j’étais parti sur l’utilisation de la balide object, qui demande d’utiliser un fichier externe (contenant uniquement la déclaration SVG) ou une data-URI pour afficher le SVG initial. D’ailleurs le data-URI n’est pas possible, car Webkit refuse tout mimetype navigable dans les data-URI, ce qui oblige donc à utiliser un fichier externe. Il faut aussi ajouter un évènement load sur notre object pour savoir quand on peut commencer à ajouter des éléments, etc.

Cette solution marche aussi, mais fort compliquée. Je pensais alors que SVG était particulièrement pénible à injecter dans les pages HTML, comparé à la balise CANVAS par exemple. Bah j’avais tord, en fait c’est super simple avec HTML 5 🙂

Créez un site Web ou un blog gratuitement sur WordPress.com.

Retour en haut ↑