Saltar al contenido

textLength y lengthAdjust

Forzar un texto a una anchura exacta: qué distorsiona cada modo, cuándo es la herramienta correcta y cuándo produce tipografía inaceptable, y su interacción con las fuentes.

Forzar la anchura

textLength declara la longitud que debe ocupar el texto en el eje de avance, en unidades de usuario. El motor ajusta el texto para que la cumpla.

HTML
<svg viewBox="0 0 220 90" width="440">  <line x1="10" y1="20" x2="190" y2="20" stroke="#45475a" />  <g font-size="18" fill="#cdd6f4" font-family="system-ui, sans-serif">    <text x="10" y="40">Sin forzar</text>    <text x="10" y="70" textLength="180">Forzado a 180</text>  </g></svg>

El segundo texto llega exactamente hasta la marca de 180 unidades, sea cual sea su anchura natural.

Funciona tanto para estirar como para encoger. Y funciona sobre tspan además de sobre text, lo que permite ajustar una parte de la cadena:

HTML
<text x="10" y="30" font-size="18">  Total: <tspan textLength="60">1.284</tspan> €</text>

Ese patrón es muy útil en tablas y en listas de cifras: fuerza a que todos los números ocupen lo mismo y queden alineados aunque tengan distinto número de dígitos, sin fuente monoespaciada.

Los dos modos

lengthAdjust decide cómo se consigue la anchura pedida.

spacing (el valor por omisión) reparte la diferencia entre los espacios de avance de los glifos. Las letras conservan su forma y su anchura; lo que cambia es la separación. Es el equivalente al letter-spacing de CSS, con la diferencia de que aquí el valor se calcula para dar exactamente la anchura pedida.

spacingAndGlyphs escala los glifos también, horizontalmente. Las letras se estiran o se comprimen.

HTML
<g font-size="18" fill="#cdd6f4">  <text x="10" y="30" textLength="200" lengthAdjust="spacing">Espaciado</text>  <text x="10" y="60" textLength="200" lengthAdjust="spacingAndGlyphs">Escalado</text></g>

La diferencia es brutal cuando el factor se aleja de 1. Con spacing, un texto muy estirado se ve con las letras separadas: es legible y a veces incluso elegante. Con spacingAndGlyphs, las letras se deforman: los trazos verticales engordan o adelgazan y los redondeos se convierten en óvalos. Es la deformación que cualquier tipógrafo considera un error, y la que la gente reconoce inmediatamente como «esa fuente está estirada».

La regla:

  • Para encajar una etiqueta: spacing, y solo si el ajuste es pequeño (digamos, menos de un 15 por ciento).
  • Para un efecto deliberado de letras separadas: spacing, sin límite.
  • Para escalar un logotipo tipográfico a un ancho exacto: spacingAndGlyphs, pero mejor un transform: scaleX() sobre el elemento, que es más explícito.
  • Para texto de lectura: ninguno de los dos. Mide y reduce el tamaño de fuente.

Un límite importante de spacing: si el texto tiene que encogerse mucho, el espaciado se vuelve negativo y las letras se solapan. No hay un mínimo que el motor respete: se solaparán hasta ser ilegibles. textLength no protege de nada.

La trampa de la fuente

textLength se aplica a lo que el motor renderiza. Si la fuente web aún no ha cargado, el texto se compone con la fuente de reserva y se ajusta a la anchura pedida con esa fuente. Cuando la real llega, se recompone y se vuelve a ajustar.

El resultado visible: un texto que aparece con un espaciado y cambia a otro. Como la anchura total no cambia (es la que has forzado), lo que se ve es que las letras se reorganizan dentro del mismo ancho. Es un salto sutil y molesto, y a diferencia del cambio de fuente normal no produce desplazamiento del contenido de al lado.

Curiosamente, esto convierte a textLength en una herramienta contra el desplazamiento de contenido: un texto con anchura forzada no cambia de tamaño al cargar la fuente, así que no mueve nada de lo que tiene alrededor. En un gráfico con etiquetas junto a formas, eso puede ser preferible al salto.

Si necesitas evitar el cambio por completo, la vía es esperar:

JS
await document.fonts.ready;// ahora medir y aplicar textLength

Medir de verdad

Los métodos de SVGTextContentElement son la alternativa, y conviene tenerlos a mano:

JS
const t = document.querySelector('text');t.getComputedTextLength();       // anchura real del texto renderizadot.getNumberOfChars();            // numero de caracterest.getSubStringLength(0, 5);      // anchura de los cinco primerost.getStartPositionOfChar(3);     // punto donde empieza el cuarto caractert.getExtentOfChar(3);            // caja del cuarto caracter

Con getSubStringLength se implementa un truncado con puntos suspensivos que corta en el carácter exacto, y con getExtentOfChar se coloca un cursor o un resaltado sobre una parte del texto. Son APIs poco conocidas y hacen posible casi todo lo que el formato no ofrece de serie.