SVG en Production : Performance et Sécurité 2025 — Code Minimal, Effet Maximal
Publié: 23 sept. 2025 · Temps de lecture: 5 min · Par la rédaction Unified Image Tools
TL;DR
- Normaliser chemins/transformations, vectoriser le texte si nécessaire
- Supprimer métadonnées/traces d'éditeur inutiles, éviter CLS avec viewBox et proportions
- Restreindre références ressources externes/scripts—gérer avec CSP
Liens internes : Images accessibles en pratique — Limites entre alt/décoratives/illustrations 2025, Conception de Vignettes OGP 2025 — Sans Coupure, Légères, Communicatives
Introduction
SVG est "graphiques vectoriels décrits en texte," offrant avantages de légèreté, évolutivité sans dégradation et application facile de styles. Cependant, il a des écueils comme nœuds redondants des logiciels d'édition, risques des scripts/références externes, et problèmes de performance des filtres lourds. Cet article organise de manière transversale optimisation, sécurité, livraison et accessibilité pour coût minimal, effet maximal en production.
Optimisation Performance (Régime Structure et Coordonnées)
- Optimisation automatisée par défaut avec SVGO etc. (forcer en CI)
- Configurer precision (ex., 2-3 chiffres) pour arrondir coordonnées, activer
convertPathData
/convertTransform
/mergePaths
- Supprimer traces éditeur avec
removeMetadata
/removeEditorsNSData
/cleanupIDs
- Configurer precision (ex., 2-3 chiffres) pour arrondir coordonnées, activer
- Utiliser
viewBox
comme référence, ajusterwidth/height
avec CSS par cas d'usage (responsive) - Définir explicitement
preserveAspectRatio
(ex.,xMidYMid meet
) pour prévenir distorsion/CLS - Ne pas sur-fusionner chemins, utiliser
<symbol>
pour éléments réutilisables et livraison sprite - Éviter filtres lourds/flou/dégradés multi-étapes, basculer vers alternatives bitmap ou approximations CSS
Exemple config SVGO (svgo.config.js
) :
module.exports = {
multipass: true,
js2svg: { indent: 0, pretty: false },
plugins: [
{ name: 'preset-default', params: { overrides: { removeViewBox: false } } },
'cleanupIds',
'convertPathData',
'convertTransform',
{ name: 'removeAttrs', params: { attrs: ['data-*', 'id'] } },
],
};
Stratégie Sprite (<symbol> + <use>)
Pour réduire surcharge HTTP et coûts re-rendu avec multiples icônes, consolider en un fichier au build pour cache efficace.
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-search" viewBox="0 0 24 24">...</symbol>
<symbol id="icon-close" viewBox="0 0 24 24">...</symbol>
</svg>
<!-- Usage -->
<svg class="icon" aria-hidden="true"><use href="#icon-search" /></svg>
Note : Références sprite externes (href="/sprite.svg#icon"
) ont problèmes compatibilité CORS/CSP, donc par défaut same-origin/inline.
Sécurité et Assainissement (Confinement XSS/Références Externes)
SVG a fonctionnalités dynamiques comme scripts/gestionnaires événements/foreignObject
qui peuvent devenir foyers XSS quand traités comme données d'entrée. Établir ces principes :
- Rejeter attributs
script
/foreignObject
/on*
(protection double avec build et assainisseur) - Interdire/restreindre références externes (
<use href>
,<image href>
,<link>
) à same-origin - Bloquer
javascript:
etc. dans URLs données - Fixer MIME à
image/svg+xml
pour prévenir injection contenu arbitraire
Exemple DOMPurify (Node/Edge) :
import createDOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
export function sanitizeSVG(svg) {
return DOMPurify.sanitize(svg, {
USE_PROFILES: { svg: true },
FORBID_TAGS: ['script', 'foreignObject'],
FORBID_ATTR: ['on*', 'style'], // si évitement styles inline
ALLOWED_URI_REGEXP: /^(data:image\/(svg\+xml|png|jpeg);|https?:|#)/i,
});
}
Exemple CSP (en-tête HTTP ou <meta httpEquiv>
) :
Content-Security-Policy:
default-src 'self';
img-src 'self' data: https:;
object-src 'none';
script-src 'self';
style-src 'self' 'unsafe-inline';
Livraison et Cache (Optimisation Couche HTTP)
- Content-Type :
image/svg+xml; charset=utf-8
- Activer compression texte (Brotli/gzip). Extension
.svgz
généralement inutile par coûts opérationnels - Noms fichiers versionnés avec
Cache-Control: max-age=31536000, immutable
<svg>
inline est rapide pour affichage initial mais noter réutilisabilité/cache limité (petites icônes seulement)- Références externes livrées same-origin pour éviter CORS. SRI généralement inutile pour same-origin
SVG inline Next.js (wrapper accessible) :
type Props = { title?: string; desc?: string; focusable?: boolean } & React.SVGProps<SVGSVGElement>;
export function Icon(props: Props) {
const { title, desc, focusable = false, ...rest } = props;
const titleId = title ? 'svg-title' : undefined;
const descId = desc ? 'svg-desc' : undefined;
return (
<svg role="img" aria-labelledby={[titleId, descId].filter(Boolean).join(' ') || undefined} focusable={focusable} {...rest}>
{title && <title id={titleId}>{title}</title>}
{desc && <desc id={descId}>{desc}</desc>}
{/* ...chemins... */}
</svg>
);
}
Accessibilité (Sémantique et Gestion Focus)
- Graphiques significatifs obtiennent
<title>
/<desc>
avecrole="img"
, décoratifs utilisentaria-hidden="true"
/focusable="false"
- Lors vectorisation texte, vérifier lisibilité et netteté contour au zoom (alternatives hinting)
- Animations conformes
prefers-reduced-motion
, respectant préférences utilisateur
Fallbacks et Alternatives
- Environnements legacy obtiennent alternatives PNG/WebP (génération bitmap automatisée au build)
- Utiliser
<picture>
pour commutation par cas d'usage ounoscript
fail-safe pour décorations non-critiques
<picture>
<source type="image/svg+xml" srcset="/logo.svg" />
<img src="/logo.png" width="200" height="40" alt="Logo du site" />
<noscript><img src="/logo.png" alt="Logo du site" /></noscript>
</picture>
Études de Cas (Bref)
Cas 1 : Rendu lourd par sortie éditeur brute
- Symptôme : Groupes excessifs/précision coordonnées, usage filtres lourds ralentissant rendu initial
- Solution : SVGO avec precision=3,
convertPathData
/mergePaths
, élimination filtres - Résultat : 42% réduction fichier, amélioration TTI, usage CPU moindre au re-rendu
Cas 2 : Référence sprite externe bloquée par CSP
- Symptôme :
<use href="/sprite.svg#icon">
bloqué par CSP, icônes manquantes - Solution : Basculer vers sprite inline/livraison same-origin, relaxation CSP minimale
- Résultat : Affichage stable, efficacité cache améliorée
FAQ
Q. Le texte doit-il être vectorisé ?
R. Vectoriser pour logos où intégrité forme est critique. Ne pas vectoriser texte corps (nuit lisibilité/traduisibilité).
Q. Qu'en est-il d'incorporer bitmaps avec <image>
?
R. Possible mais noter gestion référence externe/URL données. Gestion espace colorimétrique/taille devient difficile, donc utiliser modérément.
Q. Comment gérer expressions filtres ?
R. Essayer alternatives CSS d'abord. Si absolument nécessaire, considérer versions rastérisées résolution moindre.
Liste Vérification (Pour Déploiement)
- [ ] Forcer SVGO en CI (precision/convertPathData/cleanupIds)
- [ ]
viewBox
/preserveAspectRatio
explicite, CLS zéro - [ ] Éliminer filtres lourds/flou (alternatives raster si nécessaire)
- [ ] Interdire
script
/foreignObject
/on*
, appliquer assainissement + CSP - [ ] Livraison same-origin,
image/svg+xml
+ compression + cache long terme - [ ] Accessibilité (title/desc/role/focusable) et fallbacks prêts