HTML utilise des caractères ordinaires pour deux rôles différents: le contenu visible et la structure du document. Le signe inférieur peut faire partie d’une formule, mais il peut aussi ouvrir une balise. L’esperluette peut apparaître dans un nom, mais elle peut aussi introduire une référence de caractère. Les entités HTML, plus exactement les character references, permettent d’exprimer un caractère littéral sans que le parseur lui donne un rôle de syntaxe.
Texte et markup partagent le même canal
Le navigateur lit HTML selon le contexte. Dans un texte, < produit un < visible et & produit une esperluette. Les références nommées comme © sont pratiques pour certains symboles; les références numériques pointent vers un code point Unicode.
Avec UTF-8, la plupart des caractères peuvent être écrits directement. Les entités restent utiles pour les caractères significatifs dans la syntaxe ou pour rendre une intention claire dans le source.
L’escaping dépend du contexte
Le texte entre balises, une valeur d’attribut, une URL, du CSS et du JavaScript ne suivent pas les mêmes règles. Échapper une guillemet dans un attribut ne sécurise pas une chaîne placée dans un script.
Les moteurs de templates sûrs choisissent l’encodeur selon le contexte. Concaténer du HTML à la main ou déplacer une valeur déjà échappée d’un contexte à un autre crée des bugs.
Encoder n’est pas assainir
Encoding affiche une donnée comme du texte. Si l’utilisateur tape <strong>, il voit ces caractères, pas un élément gras. Sanitization est différente: elle autorise un sous-ensemble de HTML réel après parsing et suppression des éléments dangereux.
Si le rich text n’est pas nécessaire, tout échapper est plus simple. Décoder avant un rendu raw peut réintroduire du markup dangereux.
Le double encoding révèle une responsabilité floue
Si une valeur échappée est échappée de nouveau, l’utilisateur voit des séquences comme &lt;. Cela arrive lorsque base, API et template croient tous posséder l’escaping.
Le modèle le plus sain stocke le texte sémantique et l’échappe à la frontière de sortie. Les formes propres à une présentation ne devraient pas devenir la valeur canonique d’un champ ordinaire.
Source et DOM ne montrent pas la même étape
Le source de la réponse montre ce que le serveur a envoyé. Le DOM montre ce que le navigateur a compris après parsing et récupération d’erreurs. Comparer les deux aide à localiser le problème: stockage, sérialisation, template ou parseur.
Les validateurs détectent un source mal formé; les tests de rendu confirment le comportement réel. Les composants critiques méritent les deux vérifications.
Les éditeurs peuvent transformer le contenu
Un éditeur visuel peut remplacer des caractères par des entités, réordonner des attributs ou normaliser le HTML au moment de sauvegarder. Si ouvrir et sauvegarder sans modification produit un grand diff, l’audit devient confus.
Pour du texte simple, l’éditeur devrait travailler avec une valeur sémantique. Pour du HTML riche, la politique de normalisation doit être documentée.
Toutes les entités n’améliorent pas la lisibilité
Transformer chaque caractère non ASCII en entité rend le source long et difficile à relire. Le UTF-8 direct est souvent préférable pour du texte normal. Les entités sont surtout utiles pour les caractères de syntaxe ou les symboles ambigus.
L’objectif n’est pas de maximiser leur nombre. L’objectif est de produire un document lisible, stable et correctement parsé.
Les entités sont un outil de syntaxe
Elles ne chiffrent rien, ne cachent rien et n’autorisent rien. Elles permettent à du contenu et à une structure de coexister dans un document texte. Utilisées avec un escaping contextuel et une sanitization explicite, elles évitent à la fois artefacts visibles et injections.
Les tests doivent utiliser des caractères difficiles
Un jeu de fixtures devrait contenir esperluettes, chevrons, guillemets, apostrophes, texte non latin et séquences qui ressemblent déjà à des entités. Il devrait aussi couvrir le passage par éditeur et API. Ces exemples protègent contre les régressions lors d’un changement de template engine.
Tester uniquement des mots simples donne une fausse confiance. Les bugs apparaissent quand le contenu réel touche la syntaxe.
L’ownership réduit les corrections contradictoires
Une équipe doit savoir quelle couche stocke, quelle couche sérialise et quelle couche échappe. Sans ownership, chaque écran ajoute sa propre correction locale. Le résultat est un contenu qui semble réparé à un endroit et cassé ailleurs.
Cette responsabilité peut être renforcée par les types. Une valeur plain text, une valeur HTML assainie et une URL ne devraient pas circuler comme trois chaînes indistinguables. Les noms de champs et helpers doivent rendre le type visible.
Cette visibilité aide aussi les revues de code. Un reviewer peut repérer immédiatement qu’une valeur HTML est envoyée dans un contexte texte ou qu’un texte brut est rendu raw.
Les contrats d’API devraient reprendre la même distinction. Un client ne devrait jamais déterminer le type d’un champ en cherchant des chevrons ou des entités dans son contenu.
La règle pratique est simple: stocker du texte sémantique, échapper pour le contexte exact, et n’afficher du HTML raw que lorsqu’il est explicitement autorisé et assaini.