Retour au cours

frontend / html

SVG inline et manipulation

Leçon 181 exercice

Explication

Ce que vous allez apprendre

  • Comprendre pourquoi le SVG reste manipulable en DOM contrairement au Canvas
  • Utiliser viewBox pour définir un repère de coordonnées interne indépendant de l'affichage
  • Styliser un SVG inline en CSS, y compris au survol avec :hover
  • Créer dynamiquement un élément SVG en JavaScript avec createElementNS
  • Réutiliser des formes avec <defs>/<use> et faire hériter une couleur avec currentColor

Dans quel contexte ?

Un designer demande qu'une icône de panier dans header.html change de couleur au survol de la souris, en cohérence avec la charte graphique. Si l'icône est une image PNG classique, c'est impossible sans dupliquer le fichier ; en l'intégrant comme SVG inline avec fill="currentColor", un simple .icone:hover { color: #1d4ed8; } en CSS suffit, exactement comme pour n'importe quel texte du DOM.

Étape 1 : la limite du Canvas, rappel rapide

La leçon précédente montrait le Canvas, qui dessine des pixels sans laisser de trace structurée derrière lui — impossible de "cliquer sur le cercle" après coup, puisqu'il n'existe plus qu'une image.

Étape 2 : l'approche inverse du SVG

Le SVG prend l'approche inverse : chaque forme reste un vrai élément du DOM, aussi manipulable qu'une balise HTML classique. Un <circle> peut recevoir un addEventListener, être ciblé en CSS, exactement comme un <div>.

Étape 3 : pourquoi c'est "vectoriel"

La différence fondamentale avec une image bitmap (JPEG, PNG) est que le SVG décrit des FORMES mathématiques — un cercle a un centre et un rayon — plutôt que des pixels fixes.

Étape 4 : la conséquence concrète de ce choix

Résultat : agrandir un SVG à n'importe quelle taille ne le rend jamais flou ni pixelisé, contrairement à une photo zoomée. C'est pour cela que les icônes et logos modernes utilisent presque toujours ce format.

CritèreCanvasSVG
NaturePixels (bitmap)Formes vectorielles (DOM)
Manipulable après dessin ?Non (image figée)Oui (querySelector, CSS, events)
AgrandissementDevient flou/pixeliséToujours net
Cas d'usage typiqueJeux, animations complexesIcônes, logos, graphiques interactifs

Étape 5 : le repère caché mais essentiel, viewBox

Il reste un attribut à comprendre absolument : viewBox définit un système de coordonnées interne, indépendant de la taille d'affichage réelle en pixels CSS. Comme dessiner sur du papier millimétré dont on change ensuite la taille d'impression sans toucher au dessin.

Le piège de la création dynamique

Un dernier piège technique : créer un élément SVG en JavaScript avec le simple document.createElement échoue silencieusement, sans erreur visible. La raison : le SVG appartient à un "espace de noms" XML différent du HTML classique.

Il faut donc utiliser createElementNS en précisant explicitement ce namespace pour que le navigateur reconnaisse l'élément comme du SVG valide.

Piège fréquent

document.createElement("circle") ne lève aucune erreur mais crée un élément HTML inconnu, invisible et sans effet, jamais un vrai cercle SVG. Utilisez systématiquement document.createElementNS("http://www.w3.org/2000/svg", "circle") pour créer un élément SVG en JavaScript.

Et ensuite ?

Une fois SVG et Canvas maîtrisés, la prochaine leçon aborde un sujet de sécurité important : intégrer du contenu tiers avec les iframes et le sandboxing.

Commandes & code

SVG inline et manipulation

Graphiques vectoriels directement dans le DOM, stylables en CSS et manipulables en JS comme n'importe quel élément.

html
<!-- SVG inline : fait partie du DOM, contrairement à <img src="x.svg"> -->
<svg viewBox="0 0 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <!-- viewBox définit le repère interne : indépendant de width/height affichés -->
    <circle cx="100" cy="100" r="80" fill="#2563eb" class="cercle-principal" />
    <rect x="60" y="60" width="80" height="80" fill="#f59e0b" opacity="0.8" />
    <text x="100" y="105" text-anchor="middle" fill="#fff" font-size="14">SVG</text>
</svg>
html
<!-- Chemins : la primitive la plus puissante, base de toute icône complexe -->
<svg viewBox="0 0 24 24" width="24" height="24">
    <path
        d="M12 2 L15 9 L22 9 L16.5 13.5 L18.5 21 L12 17 L5.5 21 L7.5 13.5 L2 9 L9 9 Z"
        fill="#f59e0b"
    />
    <!-- M = moveto, L = lineto, Z = close path — commandes en majuscule = coordonnées
         absolues, en minuscule = relatives à la position courante -->
</svg>

<!-- Dégradés et réutilisation via <defs>/<use> -->
<svg viewBox="0 0 200 100" width="200" height="100">
    <defs>
        <linearGradient id="degrade1" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stop-color="#2563eb" />
            <stop offset="100%" stop-color="#22c55e" />
        </linearGradient>

        <circle id="pastille" r="10" fill="#fff" />
    </defs>

    <rect width="200" height="100" fill="url(#degrade1)" />
    <use href="#pastille" x="30" y="50" />
    <use href="#pastille" x="100" y="50" />
    <use href="#pastille" x="170" y="50" />
</svg>
css
/* SVG inline : stylable comme du HTML classique, y compris au survol */
.cercle-principal {
    transition: r 0.2s ease, fill 0.2s ease;
}
.cercle-principal:hover {
    r: 90;
    fill: #1d4ed8;
}

/* currentColor : hérite la couleur du texte environnant, très utile pour les icônes */
svg.icone { fill: currentColor; width: 1em; height: 1em; }
js
// Manipulation en JS : SVG = DOM, donc querySelector/setAttribute fonctionnent
const cercle = document.querySelector(".cercle-principal");

cercle.addEventListener("click", () => {
    const rayonActuel = Number(cercle.getAttribute("r"));
    cercle.setAttribute("r", rayonActuel === 80 ? 60 : 80);
});

// Créer un élément SVG dynamiquement : namespace obligatoire,
// createElement seul (sans NS) échoue silencieusement sur du SVG
const NS = "http://www.w3.org/2000/svg";
const nouveauCercle = document.createElementNS(NS, "circle");
nouveauCercle.setAttribute("cx", "50");
nouveauCercle.setAttribute("cy", "50");
nouveauCercle.setAttribute("r", "20");
nouveauCercle.setAttribute("fill", "#ef4444");
document.querySelector("svg").appendChild(nouveauCercle);

Résumé

  • Un SVG inline fait partie du DOM : querySelector, addEventListener, CSS s'y appliquent directement.
  • viewBox définit le système de coordonnées interne, indépendamment de width/height en pixels CSS.
  • Créer un élément SVG en JS exige createElementNS avec le namespace SVG, pas createElement.
  • currentColor sur fill/stroke fait hériter une icône SVG de la couleur du texte parent.

Exercices pratiques

1 disponible
1

Mission : rendre l'icône panier de header.html réactive au survol

Objectif : Remplacer une icône PNG figée par un SVG inline capable de changer de couleur au survol via CSS pur.

Contexte

Un designer demande qu'une icône de panier dans header.html change de couleur au survol de la souris, en cohérence avec la charte graphique. L'icône est actuellement une image <img src="panier.png">. Le designer a aussi remarqué que redimensionner cette icône en CSS (width: 32px) la fait parfois apparaître rognée plutôt que proprement mise à l'échelle sur d'autres icônes SVG du site.

Ta mission : intégrer l'icône en SVG inline, stylable au survol.

Résoudre l’exercice →