Aller au contenu
OneKitly

Les fausses polices de ton bio ne sont pas des polices : ce que sont vraiment ces caractères

Publié le 26/09/2025 · 14 min de lecture · Outils texte & langage

Daniel Okonkwo

Daniel OkonkwoDéveloppeur front-end et rédacteur Tech chez OneKitly

Performance web · Formats de fichiers

Vérifié à partir de 5 sources

Voir le profil
En bref

Les générateurs qui promettent cent polices pour ton profil ne changent aucune police. Ils remplacent chaque lettre par un caractère différent qui se trouve être dessiné dans un autre style. Passe « OneKitly » dans un générateur gras et tu obtiens les points de code U+1D400 U+1D425 U+1D425 U+1D422 U+1D427 — aucun n'est la lettre A, l, l, i ou n. Ce sont MATHEMATICAL BOLD CAPITAL A et ses voisins, des caractères ajoutés par le standard Unicode pour qu'un article de physique distingue un vecteur gras d'un scalaire italique. Comme ce sont des caractères différents, tout ce qui compare du texte cesse de fonctionner : "OneKitly".includes(gras) renvoie false, toLowerCase() ne les touche pas, /\w/ et /[a-zA-Z]/ ne les reconnaissent pas, et Number("𝟏𝟐𝟑") vaut NaN. Une phrase de 33 caractères passe de 33 à 117 octets UTF-8. Les technologies d'assistance lisent le tampon qu'on leur donne, et ces caractères ne portent aucune prononciation : une bio écrite ainsi est annoncée de travers ou ignorée. Le bloc compte aussi 28 trous là où des lettres étaient déjà codées ailleurs, d'où la table de rustines de chaque générateur. La normalisation NFKC ramène tout à de l'ASCII, si bien qu'une plateforme qui normalise supprime l'effet en silence.

Un 𝐀 qui semble gras n'est pas la lettre A en gras — c'est U+1D400, un caractère distinct inventé pour les mathématiques. Nous avons imprimé les points de code, mesuré le coût en octets, cassé la recherche, le tri et le comptage de mots avec, et scanné le bloc pour trouver ses 28 trous.

Ce que fait réellement le générateur

Une police est un fichier. Elle contient des contours et associe la lettre A à une forme. Choisir une police grasse ne change pas la lettre A ; cela change la façon dont la lettre A est dessinée. Chacun des styles proposés par un générateur de bio fonctionne à l'inverse : la lettre est remplacée, et le dessin est celui que la police de la plateforme avait déjà pour le remplaçant.

Imprime les points de code et la substitution saute aux yeux. Le mot OneKitly en style gras vaut U+1D400 U+1D425 U+1D425 U+1D422 U+1D427 ; en ajouré U+1D538 U+1D55D U+1D55D U+1D55A U+1D55F ; en chasse fixe U+1D670 U+1D695 U+1D695 U+1D692 U+1D697. Cinq lettres visibles, cinq points de code, aucun dans la plage ASCII. En JavaScript la chaîne annonce .length 10, car chacun de ces caractères occupe deux unités UTF-16.

Ils coûtent aussi plus cher à stocker. La phrase « Building tools for six languages. » fait 33 caractères et 33 octets UTF-8 parce qu'elle est en pur ASCII. La même phrase en gras fait toujours 33 caractères, mais 61 unités UTF-16 et 117 octets UTF-8 — trois fois et demie la charge utile pour les mêmes mots. Sur une plateforme qui mesure une bio en octets plutôt qu'en caractères, c'est l'essentiel de ton budget dépensé pour rien.

Tout ce qui compare du texte cesse de correspondre

La recherche de sous-chaîne échoue d'abord. "OneKitly".includes(gras) renvoie false, et l'inverse aussi, car aucun point de code n'est partagé. Une recherche interne, le rechercher-sur-la-page du navigateur, une clause LIKE en base et un index de hashtags se ramènent à la même comparaison, et tous échouent. Si ton nom affiché est écrit en gras mathématique, quelqu'un qui tape ton vrai nom dans la barre de recherche ne te trouvera pas.

La conversion de casse ne fait rien. gras.toLowerCase() renvoie exactement la même chaîne, car les correspondances de casse d'Unicode pour les alphanumériques mathématiques associent chaque caractère à lui-même. Une recherche insensible à la casse qui met les deux côtés en minuscules échoue donc quand même. La seule chose qui marche, c'est la collation : Intl.Collator("en", { sensitivity: "base" }).compare("𝐀", "A") renvoie 0, car les tables de collation d'ICU replient les lettres stylisées sur leurs lettres de base. C'est utile à savoir, car cela explique pourquoi la même chaîne est trouvable dans un produit et invisible dans un autre — tout dépend de si le chemin de recherche passe par un collateur ou par une égalité de chaînes.

Les classes de caractères se contredisent. /[a-zA-Z]/.test("𝐀") est faux, /\w/u.test("𝐀") est faux, mais /\p{L}/u.test("𝐀") est vrai — le caractère est bien une lettre selon la catégorie générale d'Unicode (Lu pour la capitale, Ll pour la minuscule), il n'est simplement pas une lettre ASCII. Les chiffres se comportent pareil : /\d/u.test("𝟏") est faux tandis que /\p{Nd}/u.test("𝟏") est vrai, et Number("𝟏𝟐𝟑") vaut NaN alors que la même chaîne après NFKC s'analyse en 123. Deux validateurs écrits par deux équipes rendront donc des verdicts opposés sur la même bio.

Le tri partage la différence. Un Array.prototype.sort() nu compare des unités UTF-16, si bien que ["𝐁rown", "Adams", "Clark"] ressort en Adams, Clark, 𝐁rown — le nom stylisé est exilé en fin de liste parce que U+1D400 est numériquement plus grand que toute lettre ASCII. Passe à localeCompare et les trois mêmes donnent Adams, 𝐁rown, Clark, ce qu'attend un lecteur. Aucun n'a tort ; ils répondent à des questions différentes, et un annuaire qui utilise le rapide te classera nulle part.

Le coût d'accessibilité, dit simplement

Un lecteur d'écran ne voit pas ton bio. Il reçoit la suite de caractères que la plateforme a stockée et la remet à un synthétiseur vocal, qui cherche chaque caractère dans un dictionnaire de prononciation. Ce dictionnaire est fait pour les lettres avec lesquelles on écrit. U+1D400 n'en fait pas partie. Le synthétiseur a trois options : lire à voix haute le nom Unicode du caractère, lire un substitut générique, ou l'ignorer. Les trois arrivent en pratique, et laquelle dépend du lecteur, de la voix et du niveau de verbosité — pas de ce que l'auteur contrôle.

Le coût est facile à sous-estimer car la panne est invisible pour celui qui l'a causée. Tu vois un nom élégant. Un lecteur aveugle peut entendre trente noms de caractères à la suite, ou voir le nom de ton compte disparaître entièrement, laissant une carte avec une image et aucun titre. Aucun réglage ne permet à ce lecteur d'y remédier, car du point de vue de la machine le texte dit réellement autre chose. C'est tout l'argument ; il n'a besoin d'aucune morale par-dessus.

Une famille est pire que les autres. Les jeux cerclés et cerclés inversés — Ⓐ U+24B6, 🅐 U+1F150 — ne sont pas du tout des lettres : leur catégorie générale est So, symbole/autre. Un logiciel qui filtre un champ pour ne garder que lettres et espaces les supprimera, et un logiciel qui compte les lettres en comptera zéro.

Les 28 trous du bloc, et pourquoi chaque générateur a une table de rustines

Le bloc Mathematical Alphanumeric Symbols va de U+1D400 à U+1D7FF, soit 1 024 points de code. En le scannant à la recherche de caractères assignés, on en trouve 996 : 28 emplacements sont donc vides. Il reste 652 lettres latines (treize styles de 52, moins les manquantes), 294 caractères grecs et apparentés, et 50 chiffres en cinq styles.

Quatre des 28 sont du simple remplissage réservé : U+1D6A6 et U+1D6A7 se placent entre le j italique sans point et l'alpha capitale grasse, et U+1D7CC et U+1D7CD entre le digamma minuscule gras et le chiffre zéro gras. Les 24 autres sont des emplacements de lettres délibérément laissés vides parce que ce caractère exact avait déjà été codé des années plus tôt dans le bloc Letterlike Symbols, en U+2100–U+214F.

La liste est assez courte pour être donnée en entier. Le h italique manque parce qu'il existait déjà en U+210E PLANCK CONSTANT. Au script manquent B, E, F, H, I, L, M, R (ils vivent en U+212C, U+2130, U+2131, U+210B, U+2110, U+2112, U+2133, U+211B) et les minuscules e, g, o (U+212F, U+210A, U+2134). Au fraktur manquent C, H, I, R, Z (U+212D, U+210C, U+2111, U+211C, U+2128). À l'ajouré manquent C, H, N, P, Q, R, Z (U+2102, U+210D, U+2115, U+2119, U+211A, U+211D, U+2124) — les lettres de théorie des ensembles que tout mathématicien avait déjà.

C'est pour cela que le bloc trahit son origine. Un générateur qui associe les lettres par simple arithmétique — prendre le point de code de A, ajouter le décalage du style — produit des points de code non assignés pour ces 24 lettres, et un point de code non assigné s'affiche en carré vide. Un bon générateur embarque la table de rustines. Un générateur bâclé non, d'où ces textes en script troués exactement là où devraient être un E ou un R.

Là où ces caractères sont la bonne réponse

Rien de tout cela ne fait de ces caractères une erreur. Ils existent parce qu'en mathématiques le style est le sens. Un R gras et un R italique ne sont pas le même symbole lu de deux façons ; ce sont deux symboles. ℝ désigne les réels, R peut être un anneau, et un vecteur gras n'est pas le scalaire écrit avec la même lettre. Coder les styles comme des caractères distincts, c'est ce qui permet à une formule de survivre à une copie d'un article vers un courriel sans perdre son contenu.

C'est aussi le test pour savoir si tu les emploies bien. Si le style porte une information qui serait perdue sans lui, le caractère est le bon outil. Si le style n'est qu'un ornement sur de la prose ordinaire, alors des lettres normales plus une vraie mise en forme — le gras que produit ton éditeur, qui laisse la lettre A être la lettre A — est le bon outil, et c'est le seul que lecteur d'écran, index de recherche et routine de tri savent tous traiter.

NFKC, et les plateformes qui suppriment l'effet sans te prévenir

Unicode définit une décomposition de compatibilité pour chacun de ces caractères : le standard lui-même enregistre que U+1D400 est une variante de mise en forme de A. La forme de normalisation NFKC applique ces décompositions puis recompose ; ainsi gras.normalize("NFKC") sur notre phrase de test renvoie l'original ASCII, caractère pour caractère — nous avons comparé les deux chaînes, elles sont égales. Il en va de même du texte pleine chasse (U+FF21 devient A), des lettres cerclées (U+24B6 devient A) et des lettres modificatives en exposant (U+1D2C devient A).

Beaucoup de services normalisent à l'entrée, en général pour empêcher deux comptes d'avoir des noms d'apparence identique. Quand c'est le cas, le style que tu as collé a disparu au moment de l'enregistrement, et rien ne t'le dit : tu soumets une bio stylisée et tu en récupères une ordinaire. Rien n'est cassé ; la plateforme a simplement demandé à la base de caractères ce que ton texte disait vraiment, et a stocké cette réponse.

Deux familles survivent à NFKC, et savoir lesquelles est utile. Les petites capitales — ᴀ est U+1D00 LATIN LETTER SMALL CAPITAL A — sont des lettres phonétiques des extensions API, sans aucune décomposition de compatibilité : elles traversent la normalisation intactes. Les lettres cerclées inversées aussi, 🅐 U+1F150 et compagnie. Aux yeux du standard, ce ne sont pas des variantes stylistiques de A ; ce sont des caractères à part entière. Elles sont donc plus durables et pas plus lisibles, ce qui est l'échange sur lequel repose toute la catégorie.

Une règle pratique pour un profil

Garde en lettres ordinaires les champs sur lesquels on effectue des recherches : ton nom, ton identifiant, les mots que quelqu'un taperait pour te trouver. Ce sont les champs où la substitution te coûte quelque chose de mesurable. Si tu veux une fioriture, mets-la là où personne n'interroge — un séparateur, un unique caractère décoratif — et laisse les mots autour en clair.

Et garde une copie de la version en clair. Puisque la transformation est une table de correspondance, le retour en est une aussi : normalise en NFKC et tu récupères exactement l'original pour les familles mathématique, pleine chasse, cerclée et exposant. Pour les petites capitales et les cerclées inversées, il te faut une table inverse, car la normalisation ne le fera pas à ta place.

Une seule lettre A visible, six façons de la coder — mesuré avec Node 26 et unicodedata 15.1 de Python
CaractèrePoint de codeNom UnicodeCatégorieAprès NFKC
AU+0041LATIN CAPITAL LETTER ALu (lettre)A (inchangé)
𝐀U+1D400MATHEMATICAL BOLD CAPITAL ALu (lettre)A
𝔸U+1D538MATHEMATICAL DOUBLE-STRUCK CAPITAL ALu (lettre)A
U+FF21FULLWIDTH LATIN CAPITAL LETTER ALu (lettre)A
U+24B6CIRCLED LATIN CAPITAL LETTER ASo (symbole, pas une lettre)A
U+1D00LATIN LETTER SMALL CAPITAL ALl (lettre)ᴀ (survit)
Générateur de police styléeTransforme du texte en Unicode gras, italique ou monospace pour tes bios (𝗚𝗿𝗮𝘀, 𝘐𝘵𝘢𝘭𝘪𝘲𝘶𝘦).Essayer l'outil

Questions fréquentes

Une bio en fausse police nuit-elle à ma portée ?
Elle te retire de la recherche textuelle sur ces mots, ce qui est mesurable et indépendant de tout algorithme de classement. "OneKitly".includes(gras) est faux, donc une requête sur ton nom en clair ne peut pas correspondre à un nom stylisé par sous-chaîne. Qu'une plateforme donnée compense dépend de si elle normalise ou collationne avant d'indexer, et les plateformes ne le publient pas. La lecture prudente : tout mot par lequel tu veux être trouvé doit être écrit en lettres ordinaires.
Pourquoi certaines lettres s'affichent-elles en carrés vides ?
Deux raisons différentes, d'apparence identique. Soit le générateur a émis l'un des 28 points de code non assignés du bloc — le plus souvent une lettre script, fraktur ou ajourée parmi les 24 trous — soit le caractère existe mais la police de l'appareil du lecteur n'a pas de glyphe pour lui. Le premier cas est un bug du générateur et se voit chez tout le monde ; le second dépend de l'appareil, d'où le même message impeccable sur ton téléphone et cassé sur celui d'un autre.
Comment reconvertir du texte stylisé en lettres normales ?
Pour les familles mathématique, pleine chasse, cerclée et exposant, un seul appel suffit : texte.normalize("NFKC"). Nous avons vérifié qu'il restitue une phrase entière exactement — la phrase grasse normalisée est égale à l'original ASCII. Les petites capitales et les cerclées inversées n'ont aucune décomposition de compatibilité et survivent à la normalisation : elles exigent une table inverse explicite. Un outil de conversion embarque les deux chemins ; un normalize d'une ligne couvre la majorité.
Existe-t-il un style sans risque ?
Pas au sens d'être invisible pour les logiciels — chacun d'eux change les points de code, et c'est tout le mécanisme. Ce qui varie, c'est ce que tu perds. Substituer un caractère décoratif entre deux mots normaux ne coûte presque rien. Substituer tout un nom affiché coûte la recherche, le tri et la capacité des technologies d'assistance à le lire. L'ampleur du dommage suit le nombre de lettres substituées : utilise-les au caractère, pas à la phrase.
Pourquoi mon texte stylisé revient-il parfois en clair après enregistrement ?
Le service l'a normalisé. NFKC est la façon standard de décider si deux chaînes sont « le même texte », et les plateformes l'appliquent aux noms affichés et aux identifiants pour empêcher l'usurpation par ressemblance. Une fois appliqué, U+1D400 devient A et il n'y a plus rien à annuler. Rien n'est cassé et aucune erreur n'apparaît, car du point de vue de la plateforme elle a stocké exactement ce que tu as tapé — selon la définition de « ce que tu as tapé » que fournit la base de caractères.
Ces caractères comptent-ils dans une limite de caractères ?
Cela dépend entièrement de ce que la limite compte, et c'est le problème habituel des limites de caractères. En points de code, notre phrase de test fait 33 dans les deux cas. En unités UTF-16 — ce que renvoie .length en JavaScript et ce qu'utilisent beaucoup de validateurs de formulaire — la phrase en clair fait 33 et la grasse 61. En octets UTF-8, c'est 33 contre 117. Un formulaire qui te laisse taper 33 caractères ordinaires peut n'en accepter que 16 stylisés, et le compteur à côté du champ ne l'expliquera pas.

Articles qui pourraient t'intéresser

Tous les guides
GuideLes listes de tâches Markdown et ce qui s'affiche vraiment oùLes listes de tâches ne sont pas dans CommonMark. C'est une extension de GitHub Flavored Markdown, d'où des cases à cocher ici et des crochets littéraux là. La règle exacte du marqueur, l'effet de l'imbrication, et un tableau de ce qui est CommonMark, GFM ou ni l'un ni l'autre — vérifié sur les deux spécifications et quatre moteurs de rendu.ExplicationCompter des caractères face à une limite fixée par quelqu'un d'autreUn émoji vaut 1 caractère, ou 7, ou 11, ou 25, selon qui compte. Lequel ton formulaire, ta base et ta passerelle SMS veulent dire — et un test d'un seul collage pour savoir auquel tu as affaire.ExplicationComment marchent vraiment les polices Instagram (ce ne sont pas des polices)Rien n'est mis en forme. Chaque lettre est remplacée par un autre caractère Unicode qui ressemble à du gras ou du cursif — d'où un lecteur d'écran qui lit du charabia et des appareils qui affichent des carrés vides.ExplicationDétecter la langue d'un texte, et pourquoi les textes courts échouentMesuré, pas affirmé : 90 phrases courtes réelles dans six langues, aucune refusée et 68 justes — 76 %, tombant à 64 % en dessous de seize lettres. Quatre des réponses fausses sont revenues avec 100 % de confiance.TutorielNuméroter les lignes d'un texte pour une relecture à plusieursLa numérotation commence à 1 et ne peut pas être mise à 0, l'alignement se fait avec des espaces et non des zéros, et l'outil de suppression annule huit des onze séparateurs sans toucher à l'indentation. Ce qu'il ne sait toujours pas faire, c'est distinguer tes numéros des siens.ExplicationCasse de phrase et casse de titre : les règles changent selon la langueLa casse de titre anglaise a trois seuils différents selon le guide de style. Le français, l'espagnol, le portugais et l'italien n'en ont aucun. L'allemand capitalise chaque nom. L'outil n'en sait rien — voici exactement ce qu'il fait.

Outils similaires

Sources

Tu as repéré une erreur dans cet article ?