- Pretext est une bibliothèque JavaScript/TypeScript pure qui calcule la hauteur et la répartition sur les lignes d’un texte multiligne sans accès au DOM, avec prise en charge des environnements navigateur et serveur
- Comme elle n’utilise pas d’API de mesure du DOM telles que getBoundingClientRect, elle élimine le coût de reflow de mise en page et garantit la précision grâce à une logique de mesure interne basée sur le moteur de polices
- Via les API prepare() / layout(), elle prétraite le texte puis effectue un calcul rapide de la hauteur par opérations arithmétiques pures en s’appuyant sur des données de largeur mises en cache
- Elle prend en charge les emoji, le texte bidirectionnel mixte (bidi) et diverses langues, tout en fournissant les mêmes résultats avec Canvas, SVG, WebGL et le rendu côté serveur
- Il s’agit d’un moteur de texte haute performance utilisable pour implémenter des mises en page UI précises comme le scroll virtualisé, la validation du débordement de texte et le placement de texte flottant
Vue d’ensemble
- Pretext est une bibliothèque JavaScript/TypeScript pure dédiée à la mesure et à la mise en page de texte multiligne, compatible avec le DOM, Canvas, SVG et même le rendu côté serveur
- Elle n’utilise pas les API de mesure du DOM (
getBoundingClientRect, offsetHeight, etc.), ce qui supprime le coût de reflow de mise en page
- Elle offre précision et rapidité grâce à une logique de mesure interne fondée sur le moteur de polices du navigateur
- Elle prend en charge toutes les langues, les emoji et le texte bidirectionnel mixte (bidi), tout en gérant les différences entre navigateurs
Installation et démos
Fonctionnalités principales
- Pretext propose deux grands modes d’utilisation
-
1. Mesure de la hauteur d’un paragraphe sans accès au DOM
prepare() prétraite le texte, normalise les espaces, sépare les segments, applique les règles de glue et effectue une mesure basée sur canvas pour renvoyer un handle opaque
layout() utilise les largeurs mises en cache pour calculer la hauteur et le nombre de lignes par opérations arithmétiques pures
- Pour un même texte et une même configuration, il n’est pas nécessaire de rappeler
prepare() ; lors d’un redimensionnement, seul layout() doit être relancé
- L’option
{ whiteSpace: 'pre-wrap' } permet de conserver tels quels les espaces, tabulations (\t) et retours à la ligne (\n)
- Résultats de benchmark :
prepare() environ 19 ms (sur 500 textes), layout() environ 0,09 ms
- La hauteur renvoyée peut être utilisée pour des fonctionnalités UI telles que :
- calcul précis des hauteurs dans la virtualisation et la gestion d’occlusion
- systèmes de mise en page pilotés en JS (par ex. masonry ou structures de type flexbox)
- validation du débordement de texte basée sur l’IA
- maintien de la position de défilement lors du chargement du texte
-
2. Construction manuelle de la mise en page d’un paragraphe
prepareWithSegments() génère des données au niveau des segments
layoutWithLines() renvoie, pour une largeur fixe, le texte de chaque ligne ainsi que ses informations de largeur
walkLineRanges() parcourt la largeur et la plage de curseurs de chaque ligne sans construire la chaîne de texte
- Exemple : il est possible de faire un ajustement de mise en page par recherche binaire en testant plusieurs largeurs afin de trouver un nombre de lignes et une hauteur appropriés
layoutNextLine() effectue la mise en page ligne par ligne lorsque la largeur varie d’une ligne à l’autre
- Exemple : placement de texte flottant pour faire couler le texte autour d’une image
- Cette approche s’applique de la même manière à Canvas, SVG, WebGL et au rendu côté serveur
Résumé de l’API
-
API de mesure de base
prepare(text, font, options?) : analyse et mesure le texte, puis renvoie un handle à transmettre à layout()
layout(prepared, maxWidth, lineHeight) : calcule la hauteur du texte et le nombre de lignes selon la largeur et la hauteur de ligne données
-
API de mise en page manuelle
prepareWithSegments(text, font, options?) : renvoie des données au niveau des segments
layoutWithLines(prepared, maxWidth, lineHeight) : inclut le texte, la largeur et les informations de curseur pour chaque ligne
walkLineRanges(prepared, maxWidth, onLine) : transmet via callback la largeur et la plage de curseurs de chaque ligne
layoutNextLine(prepared, start, maxWidth) : effectue la mise en page sous forme d’itérateur ligne par ligne
- Inclut les définitions de types
LayoutLine, LayoutLineRange, LayoutCursor
-
Autres utilitaires
clearCache() : réinitialise le cache interne
setLocale(locale?) : définit la locale et réinitialise le cache (sans effet sur l’état existant)
Limitations et points d’attention
- Pretext n’est pas un moteur de rendu de polices complet
- Propriétés CSS ciblées par défaut :
white-space: normal
word-break: normal
overflow-wrap: break-word
line-break: auto
- Avec
{ whiteSpace: 'pre-wrap' }, les espaces, tabulations et retours à la ligne sont conservés, avec application de tab-size: 8
- Sur macOS, la police
system-ui n’est pas adaptée à la précision de layout() ; il est donc recommandé d’utiliser un nom de police explicite
- En raison de
overflow-wrap: break-word, un retour à la ligne à l’intérieur d’un mot est possible sur des largeurs très étroites, mais la coupure se fait uniquement au niveau des graphèmes
Développement
- Pour l’environnement de développement et les commandes, voir
DEVELOPMENT.md
Contribution et contexte
- Reprend les idées du projet text-layout de Sebastian Markbage
- L’architecture a été développée à partir du shaping basé sur canvas
measureText, du traitement bidi de pdf.js et d’une conception de retour à la ligne en streaming
Aucun commentaire pour le moment.