L'autre jour, je travaillais sur un générateur de schéma JSON et je voulais afficher les numéros de ligne dans une
J'ai fait quelques recherches et trouvé plusieurs approches :
Je n’ai aimé aucun d’entre eux ! Le premier n'avait pas l'air net et ne correspondait pas aux styles que j'avais déjà en place pour mes éléments
Le second nécessitait beaucoup de JavaScript pour maintenir cette liste ordonnée : ajout/suppression d'éléments
J'ai donc fini par créer un hybride.
Il s'agit d'un SVG généré dynamiquement, stocké en tant que Propriété personnalisée CSS - et utilisé comme image d'arrière-plan, héritant des styles de son élément

Plongeons-nous.
Tout d'abord, la méthode principale :
lineNumbers(element, numLines = 50, inline = false)
l'élément est l'élément
Ensuite, nous définissons un préfixe pour la propriété personnalisée :
const prefix = '--linenum-';
Avant de continuer, nous vérifions s'il convient de réutiliser une propriété existante :
if (!inline) {
const styleString = document.body.getAttribute('style') || '';
const regex = new RegExp(`${prefix}[^:]*`, 'g');
const match = styleString.match(regex);
if (match) {
element.style.backgroundImage = `var(${match[0]})`;
return;
}
}
Ensuite, nous extrayons les styles de l'élément, en rendant le SVG avec la même famille de polices, la même taille de police, la même hauteur de ligne, etc. :
const bgColor = getComputedStyle(element).borderColor; const fillColor = getComputedStyle(element).color; const fontFamily = getComputedStyle(element).fontFamily; const fontSize = parseFloat(getComputedStyle(element).fontSize); const lineHeight = parseFloat(getComputedStyle(element).lineHeight) / fontSize; const paddingTop = parseFloat(getComputedStyle(element).paddingTop) / 2; const translateY = (fontSize * lineHeight).toFixed(2);
Nous avons également besoin d'un identifiant aléatoire pour notre propriété :
const id = `${prefix}${Math.random().toString(36).substr(2, 6)}`;
Et maintenant il est temps de rendre le SVG :
const svg = `<svg xmlns="http://www.w3.org/2000/svg">
<style>
svg { background: ${bgColor}; }
text {
fill: hsl(from ${fillColor} h s l / 50%);
font-family: ${fontFamily};
font-size: ${fontSize}px;
line-height: ${lineHeight};
text-anchor: end;
translate: 0 calc((var(--n) * ${translateY}px) + ${paddingTop}px);
}
</style>
${Array.from({ length: numLines }, (_, i) => `<text x="90%" style="--n:${i + 1};">${i + 1}</text>`).join("")}
</svg>`;
Décomposons-le :
Dans la section