Para dimensionar una vista previa de texto en el navegador, mide el elemento DOM maquetado en el ancho de ventana gráfica previsto. Usa Canvas para medir el texto en una sola línea. Esta guía muestra cómo comparar ambos métodos en un Mac y entender por qué sus anchos y alturas difieren.
La tarea práctica consiste en averiguar cuánto espacio necesita la etiqueta de una tarjeta sintética a medida que cambia el tamaño de la ventana gráfica del navegador. Un resultado útil registra conjuntamente la ventana gráfica, el ancho disponible para el texto, la configuración de la fuente y el cuadro medido. Es difícil reproducir un ancho sin esas condiciones.
¿Qué ancho y altura del texto deberías medir?
Las API del navegador responden a distintas preguntas sobre dimensiones. Antes de calcular nada, elige la medición que corresponda a la decisión que necesitas tomar.
| Tu pregunta | Medición | Qué representa |
|---|---|---|
| ¿Cuánto avanza horizontalmente una cadena sin ajustar a varias líneas? | Canvas measureText(text).width |
Ancho de avance del texto |
| ¿Cuáles son los límites de las formas de los glifos en Canvas? | Propiedades actualBoundingBox… de Canvas |
Límites de los glifos relativos al punto de alineación y a la línea base |
| ¿Cuánto espacio de maquetación ocupa una tarjeta? | Elemento getBoundingClientRect() |
Su cuadro delimitador de borde, incluidos el relleno y los bordes |
| ¿Dónde quedan los fragmentos de texto después del ajuste de línea? | Range getClientRects() |
Rectángulos asociados al texto seleccionado |
| ¿Qué rectángulo encierra esos fragmentos de texto? | Range getBoundingClientRect() |
Su rectángulo delimitador combinado |
El ancho de avance de Canvas y el ancho de los glifos pueden diferir: las formas en cursiva pueden sobresalir más allá de su avance. Para obtener los límites de los glifos, calcula el ancho como actualBoundingBoxLeft + actualBoundingBoxRight y la altura como actualBoundingBoxAscent + actualBoundingBoxDescent. Estas mediciones usan píxeles CSS. TextMetrics — MDN
La medición de un elemento incluye el relleno y los bordes, mientras que un Range que solo contiene texto mide el texto seleccionado usando métricas de fuente. Ninguna debe describirse como un rectángulo exacto de los píxeles pintados. La especificación del W3C define los rectángulos horizontales de texto de Range mediante el ascenso, el descenso y el avance del texto. Elemento: método getBoundingClientRect() — MDN, Módulo CSSOM View — W3C
Para una vista previa del tamaño en el navegador, usa el cuadro del elemento para asignar espacio y los rectángulos de Range para inspeccionar el flujo del texto. Mantén las mediciones de Canvas como referencia aparte para la cadena sin ajustar a varias líneas.
Configura primero la ventana gráfica y las condiciones del texto
En Chrome en tu Mac, abre DevTools, activa Toggle device toolbar y elige Responsive en Dimensions. Introduce el ancho y la altura previstos en los campos de la ventana gráfica. Chrome documenta tanto la introducción de valores numéricos como el ajuste del tamaño de la ventana gráfica arrastrando. Para una vista previa de escritorio, usa el tipo de dispositivo de escritorio cuando ese control esté disponible. Simular dispositivos móviles con el modo de dispositivo — Chrome for Developers
Distingue el ancho de la ventana gráfica del ancho disponible para el texto. Una tarjeta puede tener un ancho máximo, márgenes exteriores, relleno y bordes. Al aumentar el ancho del navegador, el área de texto dejará de crecer cuando la tarjeta alcance su ancho máximo.
Por ejemplo, supongamos que una tarjeta tiene un ancho ilustrativo de cuadro de borde de 360px, un relleno horizontal de 16px a cada lado y dos bordes de 1px. El ancho de contenido disponible es 360 − 32 − 2 = 326px. Ese es el ancho disponible para el ajuste de línea. El rectángulo delimitador del elemento sigue indicando 360px. Esto se debe al comportamiento documentado de la medición del cuadro de borde. Elemento: método getBoundingClientRect() — MDN
Usa la familia tipográfica, el grosor, el tamaño, el estilo, la altura de línea, el espaciado y las reglas de ajuste previstos. En particular, white-space: normal colapsa los espacios en blanco y permite el ajuste de línea, mientras que pre-wrap conserva los espacios en blanco y los saltos de línea del código fuente, y aun así permite el ajuste. Una vista previa con una opción no puede representar fielmente la otra. white-space — MDN
Distingue también el tamaño de fuente de la altura de línea. En escritura horizontal, line-height interviene en la altura de las cajas de línea; no describe la altura visible de las letras. Por lo tanto, una fuente de 16px con una altura de línea de 24px requiere un cálculo de altura distinto al de los límites de sus glifos en Canvas. line-height — MDN
Ejecuta una vista previa completa de texto sintético
Abre una pestaña en blanco, abre DevTools, selecciona Console y ejecuta una vez el siguiente script completo del navegador. Crea una tarjeta neutra y un informe de mediciones. No hace falta ninguna biblioteca, fuente externa, selector existente ni archivo HTML. Recarga la pestaña en blanco antes de ejecutar otra copia.
La tarjeta sigue el tamaño de la ventana gráfica hasta alcanzar un ancho de cuadro de borde de 480px. El informe se actualiza cuando cambia el tamaño de la ventana o de la ventana gráfica emulada. Este ejemplo se limita deliberadamente a un bloque de texto horizontal sencillo con estilo uniforme. Se inspeccionó el código, que depende del navegador, pero no se ejecutó en un navegador durante la preparación.
(async () => {
const text =
"Sample collection: round forms, soft gradients, and simple patterns.";
document.body.style.margin = "0";
const card = document.createElement("div");
card.textContent = text;
card.lang = "en";
card.dir = "ltr";
card.style.cssText = [
"box-sizing: border-box",
"width: min(480px, calc(100% - 48px))",
"margin: 24px",
"padding: 16px",
"border: 1px solid #777",
"font: normal 400 16px/24px Arial, sans-serif",
"font-kerning: normal",
"letter-spacing: 0px",
"word-spacing: 0px",
"white-space: normal",
"overflow-wrap: normal",
"word-break: normal",
"hyphens: none",
"color: #222",
"background: #f4f4f4"
].join(";");
const report = document.createElement("pre");
report.style.cssText =
"margin: 24px; white-space: pre-wrap; overflow-wrap: anywhere;";
document.body.append(card, report);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) {
report.textContent = "A Canvas 2D context is unavailable.";
return;
}
// Establish layout before waiting for the fonts used by that layout.
card.getBoundingClientRect();
await document.fonts.ready;
const format = value =>
Number.isFinite(value) ? value.toFixed(2) : "unavailable";
function measure() {
const style = getComputedStyle(card);
const box = card.getBoundingClientRect();
const horizontalExtras =
parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) +
parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);
const range = document.createRange();
range.selectNodeContents(card);
const textBox = range.getBoundingClientRect();
const fragments = Array.from(range.getClientRects());
ctx.font = "normal 400 16px Arial, sans-serif";
ctx.fontKerning = "normal";
ctx.direction = "ltr";
ctx.textAlign = "left";
ctx.textBaseline = "alphabetic";
const metrics = ctx.measureText(text);
const inkWidth =
metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight;
const inkHeight =
metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
report.textContent = [
"All dimensions below are CSS pixels.",
`Layout viewport: ${document.documentElement.clientWidth} x ${document.documentElement.clientHeight}`,
`Card border box: ${format(box.width)} x ${format(box.height)}`,
`Available text width: ${format(box.width - horizontalExtras)}`,
`Range bounds: ${format(textBox.width)} x ${format(textBox.height)}`,
`Range fragment count: ${fragments.length}`,
`Canvas unwrapped advance: ${format(metrics.width)}`,
`Canvas glyph bounds: ${format(inkWidth)} x ${format(inkHeight)}`,
`Computed line height: ${style.lineHeight}`
].join("\n");
}
measure();
window.addEventListener("resize", measure);
})().catch(error => console.error("Preview failed:", error));
Las llamadas a elementos y Range usan la maquetación real del navegador. Canvas mide la misma cadena sintética como un único tramo sin ajuste de línea. El estándar HTML de Canvas convierte los espacios en blanco ASCII en espacios; pasar un salto de línea a measureText() no crea un párrafo CSS con varias líneas. Estándar HTML: el elemento canvas — WHATWG
El script espera a document.fonts.ready después de establecer la maquetación. MDN indica que esta promesa se cumple cuando terminan las operaciones de carga y maquetación de las fuentes utilizadas. Esto no significa que se haya cargado cada fuente declarada ni que se muestre necesariamente la tipografía preferida originalmente. Documento: propiedad fonts — MDN
Interpreta los resultados y decide si el texto cabe
Empieza por Available text width y, a continuación, compara la altura de la tarjeta en dos tamaños de ventana gráfica. Cuando el ajuste de línea añade una línea, cambia la altura de la tarjeta, mientras que el avance sin ajuste de Canvas puede permanecer igual. Esa combinación ayuda a distinguir un cambio en el ajuste de línea de un cambio de fuente.
En este ejemplo, los siguientes anchos son cálculos ilustrativos, no resultados de mediciones de fuentes. Suponen que la ventana gráfica de maquetación tiene el ancho indicado y que los estilos del script no cambian.
| Ancho de la ventana gráfica de maquetación | Ancho del cuadro de borde de la tarjeta | Ancho disponible para el texto |
|---|---|---|
360px |
312px |
278px |
800px |
480px |
446px |
1200px |
480px |
446px |
Las dos últimas filas explican por qué ampliar la ventana del navegador puede no cambiar el ajuste de línea: la tarjeta ya alcanzó su ancho máximo. Cambiar solo la ventana gráfica no puede dar más espacio de contenido a esa tarjeta.
En un bloque sencillo que solo contiene texto uniforme, un diseño ilustrativo de tres líneas con una altura de línea de 24px ocupa 72px de espacio de caja de línea. Añade 32px de relleno vertical y 2px de bordes para obtener una altura ilustrativa de tarjeta de 106px. Este cálculo sirve para entender el resultado; cuando el contenido o el estilo se vuelven más complejos, el valor determinante es la altura medida del DOM. line-height — MDN
No interpretes automáticamente Range fragment count como un recuento universal de líneas. La API Range devuelve rectángulos de texto y elementos según sus reglas de selección. El texto enriquecido, los elementos anidados y la maquetación fragmentada pueden producir un conjunto de rectángulos más complejo. El ejemplo selecciona solo un nodo de texto sin formato para que el diagnóstico sea fácil de entender. Módulo CSSOM View — W3C
Del mismo modo, evita estimar la altura del texto ajustado a varias líneas con ceil(unwrappedWidth / availableWidth). Esa fórmula supone que el texto puede dividirse en cualquier posición horizontal. El ajuste de línea del navegador debe respetar el comportamiento de espacios en blanco y de salto configurado, así que mide el bloque ajustado. white-space — MDN
¿Qué deberías comprobar cuando las mediciones no coinciden?
Primero, comprueba los límites de la medición. Un rectángulo de tarjeta de ancho completo y un rectángulo de Range más estrecho pueden ser ambos correctos. La tarjeta reserva espacio de maquetación; Range describe el texto seleccionado. La altura de los glifos en Canvas aporta un tercer valor con otro propósito.
Después, comprueba que las fuentes estén listas. Si introduces una fuente web declarada, document.fonts.load(fontSpecification, sampleText) puede solicitar explícitamente las caras de fuente coincidentes antes de medir. Gestiona los rechazos en lugar de sustituirlos silenciosamente por un resultado correcto. El argumento de texto opcional filtra por rangos Unicode; no verifica la cobertura de glifos individuales. FontFaceSet: método load() — MDN
Conserva los límites de composición tipográfica al calcular el ancho de una etiqueta. Mide la cadena completa en lugar de sumar los anchos de caracteres medidos por separado. La especificación de Canvas prepara un tramo de glifos posicionados con la fuente y la configuración de texto actuales; su resultado es la unidad adecuada para esa cadena. Limita la comparación de Canvas de este ejemplo a la configuración de fuente indicada, en lugar de suponer que reproduce todas las características tipográficas de CSS. Estándar HTML: el elemento canvas — WHATWG
En una página existente, mide el componente real en su sitio. Mover el texto a un cuadro genérico oculto cambia las condiciones de maquetación, a menos que también reproduzcas los estilos y el contexto contenedor pertinentes. Los elementos sin cajas de maquetación asociadas no pueden proporcionar mediciones normales útiles de sus cuadros, y las transformaciones CSS afectan a los rectángulos que devuelven estas API. El ejemplo sintético evita ambas complicaciones. Módulo CSSOM View — W3C
¿Cómo puedes repetir la vista previa con varios tamaños de navegador?
Para comprobaciones puntuales, introduce manualmente cada tamaño de ventana gráfica y registra el informe. Compara los anchos alrededor del punto en que cambia el ajuste de línea, en lugar de comprobar solo un diseño muy estrecho y otro muy ancho.
Para comprobaciones repetidas, Playwright admite dimensiones explícitas de ventana gráfica y una configuración independiente de deviceScaleFactor. Su documentación también permite sobrescribir la ventana gráfica preestablecida de un dispositivo. Esto proporciona una vía de automatización compatible: establece la ventana gráfica, carga la página, espera a que se carguen las fuentes y el contenido pertinente, y luego recopila las mediciones del DOM en el navegador. Emulación — Playwright
Mantén separadas las dimensiones CSS y la densidad de píxeles de la pantalla. Playwright expone la ventana gráfica y el factor de escala como configuraciones distintas, mientras que las métricas de texto de Canvas se expresan en píxeles CSS. Una pantalla más densa no exige, por sí sola, duplicar el ancho CSS asignado a una etiqueta. Emulación — Playwright, TextMetrics — MDN
Por tanto, un resultado útil de la vista previa es un breve registro de las condiciones: navegador, ventana gráfica, texto, tipografía, ancho de contenido y altura medida de la tarjeta. Usa el resultado del DOM para dimensionar el componente con texto ajustado, conserva las métricas de Canvas para las preguntas sobre texto en un solo tramo y repite la medición en cada navegador cuya representación necesites reproducir.
Fuentes
- Módulo CSSOM View — W3C.
- Estándar HTML: el elemento canvas — WHATWG.
- TextMetrics — MDN Web Docs.
- Elemento: método getBoundingClientRect() — MDN Web Docs.
- Documento: propiedad fonts — MDN Web Docs.
- FontFaceSet: método load() — MDN Web Docs.
- white-space — MDN Web Docs.
- line-height — MDN Web Docs.
- Simular dispositivos móviles con el modo de dispositivo — Chrome for Developers.
- Emulación — Playwright.