En una línea horizontal de imágenes en línea alineadas por la línea de base, esta se encuentra en el borde inferior del margen de cada imagen. Esta guía muestra cómo localizar esa coordenada en Chrome en un Mac, comprobarla con un pequeño marcador y reconocer cuándo no se aplica este método.
¿Por qué una línea que solo contiene imágenes tiene una línea de base?
Una línea formada solo por imágenes sigue participando en el diseño en línea de CSS. Un img que se muestra correctamente es un elemento reemplazado: el navegador distribuye su caja según CSS, en lugar de tratar la imagen como texto. WHATWG documenta este comportamiento de representación en las reglas de representación de imágenes del estándar HTML.
En el diseño en línea horizontal habitual, una imagen sin línea de base de texto intrínseca usa su borde inferior del margen para alinearse por la línea de base. Por lo tanto, dos imágenes de distintas alturas alineadas por la línea de base pueden compartirla aunque sus bordes superiores estén a diferentes alturas. La regla se refiere a sus cajas; no examina la ilustración que contienen. Consulta CSS 2, alineación vertical.
Hay tres límites distintos que importan:
| Límite | Significado | ¿Es una referencia adecuada para la línea de base? |
|---|---|---|
| Borde de la ilustración visible | Donde terminan los píxeles visibles de la imagen | No; el archivo puede contener espacio transparente |
| Borde inferior de la caja de borde de la imagen | El borde inferior que devuelve getBoundingClientRect() |
Sí, tras tener en cuenta el margen inferior y confirmar la alineación por la línea de base |
| Borde inferior de la caja de línea | El límite inferior de toda la línea CSS | No; puede extenderse por debajo de la línea de base |
La fuente del elemento principal y line-height siguen siendo relevantes aunque no haya letras visibles. CSS describe una contribución invisible basada en la fuente, llamada puntal, que ayuda a establecer la altura y la profundidad mínimas de la línea. Esto explica por qué una imagen puede apoyarse en la línea de base mientras la línea conserva espacio debajo. La especificación de diseño en línea de CSS describe estas métricas tipográficas y los límites del diseño; la versión publicada consultada es un borrador de trabajo, por lo que no se debe suponer que sus funciones más recientes tengan compatibilidad universal en los navegadores.
¿Cómo se encuentra la línea de base en una página existente?
Empieza con una página que puedas inspeccionar en Chrome en tu Mac. Haz clic derecho en una imagen y elige Inspect. Chrome abre el panel Elements con ese elemento seleccionado; el panel Styles muestra el CSS aplicado. Google documenta este flujo de trabajo en Abrir Chrome DevTools.
Antes de calcular una coordenada, comprueba que se cumplan estas condiciones:
- La imagen participa en el flujo en línea normal de la línea que quieres medir.
- Su alineación efectiva es
vertical-align: baseline. - El modo de escritura es horizontal.
- Ni la imagen ni sus elementos antecesores tienen una transformación o un desplazamiento de posición visual que afecte a la medición.
- Estás midiendo la propia imagen, no un contenedor que la rodea y tenga un comportamiento propio respecto a la línea de base.
Estas condiciones delimitan el alcance del cálculo. Por ejemplo, vertical-align: bottom alinea un elemento con la parte inferior de la línea, mientras que middle usa la línea de base del elemento principal más la mitad de su altura x. Ninguno de estos valores significa que el borde inferior de la imagen identifique la línea de base del elemento principal. MDN explica estas diferencias en su referencia de vertical-align.
Cuando se cumplan esas condiciones, usa esta relación, expresando todas las distancias en píxeles CSS:
baselineY = imageBorderBoxBottom + imageMarginBottom
getBoundingClientRect() proporciona la coordenada del borde inferior de la caja de borde respecto a la ventana gráfica. Su rectángulo incluye el relleno y los bordes, así que no debes volver a sumarlos. Los márgenes quedan fuera de ese rectángulo. MDN documenta la geometría devuelta y el sistema de coordenadas en Element.getBoundingClientRect().
Como ejemplo explícitamente ilustrativo, supongamos que el borde inferior de la caja de borde de la imagen es 240.5 y que su margen inferior es 6. Por lo tanto, la línea de base está a 246.5 píxeles CSS del borde superior de la ventana gráfica. Si el borde superior de la caja de borde del contenedor es 200, esa línea de base está a 46.5 píxeles CSS del borde superior del contenedor. Esta es una distancia desde el borde de borde, no necesariamente desde el borde del contenido.
Mide otra imagen que cumpla las condiciones en la misma línea para verificar el resultado. Su borde inferior del margen debería identificar la misma línea de base, aunque su altura sea distinta. Si no coincide, inspecciona la alineación, los contenedores, el posicionamiento o el ajuste de línea antes de cambiar el CSS. Conserva los valores fraccionarios durante la comparación.
¿Cómo se puede verificar el resultado con un marcador de línea de base?
Un diagnóstico útil es un bloque en línea vacío con anchura, altura, márgenes, relleno y bordes iguales a cero, alineado por la línea de base. Como no tiene cajas de línea en el flujo, su línea de base es el borde inferior del margen. Al tener todas esas dimensiones en cero, ese borde coincide con su posición vertical medida. Esto se deriva de la regla de línea de base de los bloques en línea de CSS 2.
El siguiente programa completo para la consola crea una demostración temporal con dos imágenes rectangulares neutras y un marcador. Usa una raíz sombra para mantener los estilos internos del ejemplo separados de los selectores habituales de la página. Ejecútalo en un documento en modo estándares sin transformaciones en el documento ni en el cuerpo. Solo mide su propia fila sintética, no el contenido de una página existente.
Abre la Console con Command + Option + J, como se documenta en los atajos de DevTools de Chrome, y ejecuta el programa. No hace falta instalar ninguna biblioteca ni disponer de un archivo de imagen externo. El ejemplo genera sus rectángulos con la API Canvas estándar.
(async () => {
if (document.compatMode !== "CSS1Compat") {
throw new Error("Use a standards-mode document for this demonstration.");
}
const host = document.createElement("div");
host.style.cssText =
"all:initial;position:fixed;top:16px;left:16px;" +
"z-index:2147483647;background:white;padding:16px;" +
"color:#222;font:16px/1.5 sans-serif;";
const root = host.attachShadow({ mode: "open" });
const label = document.createElement("div");
label.textContent = "Sample A and Sample B";
const row = document.createElement("div");
row.style.cssText =
"display:block;position:relative;width:280px;" +
"margin:0;padding:0;border:0;white-space:nowrap;" +
"writing-mode:horizontal-tb;font:16px/24px sans-serif;" +
"background:#eee;";
const close = document.createElement("button");
close.textContent = "Remove demonstration";
close.addEventListener("click", () => host.remove());
root.append(label, row, close);
document.body.append(host);
try {
const images = [];
const samples = [
{ label: "Sample A", height: 32, color: "#777" },
{ label: "Sample B", height: 48, color: "#aaa" }
];
for (const sample of samples) {
const canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = sample.height;
const context = canvas.getContext("2d");
if (!context) throw new Error("A 2D canvas context is required.");
context.fillStyle = sample.color;
context.fillRect(0, 0, canvas.width, canvas.height);
const image = document.createElement("img");
image.alt = sample.label;
image.width = 64;
image.height = sample.height;
image.style.cssText =
"display:inline;vertical-align:baseline;" +
"margin:0 12px 0 0;padding:0;border:0;";
image.src = canvas.toDataURL("image/png");
row.append(image);
images.push(image);
}
await Promise.all(images.map(image => image.decode()));
if (!host.isConnected) return;
const marker = document.createElement("span");
marker.style.cssText =
"display:inline-block;vertical-align:baseline;" +
"width:0;height:0;margin:0;padding:0;border:0;" +
"font-size:0;line-height:0;";
row.append(marker);
const baselineY = marker.getBoundingClientRect().bottom;
const rowTop = row.getBoundingClientRect().top;
console.table(images.map(image => ({
sample: image.alt,
imageBottom: image.getBoundingClientRect().bottom,
markerBaseline: baselineY,
baselineFromRowTop: baselineY - rowTop
})));
const guide = document.createElement("div");
guide.style.cssText =
"position:absolute;left:0;right:0;height:1px;" +
"background:#222;pointer-events:none;";
guide.style.top = `${baselineY - rowTop}px`;
row.append(guide);
} catch (error) {
host.remove();
throw error;
}
})();
El programa espera a que ambas imágenes se decodifiquen antes de medirlas. El método documentado HTMLImageElement.decode() devuelve una promesa y puede rechazarla si falla la decodificación; en ese caso, el programa elimina el panel temporal e informa del error.
Ambas imágenes tienen un margen inferior de cero, por lo que los valores de imageBottom que se muestran deberían coincidir con markerBaseline. La guía horizontal delgada marca esa coordenada. El fondo de la fila también permite distinguir la línea de base de cualquier espacio restante debajo. Cuando termines, selecciona Remove demonstration.
Para hacer un experimento controlado, cambia el margen inferior de las imágenes del ejemplo de 0 a 6px en el estilo de la imagen. Entonces, el borde inferior de sus cajas de borde debería quedar seis píxeles CSS por encima de la línea de base del marcador. Aplica la fórmula anterior para recuperar la coordenada compartida. Así tendrás dos referencias independientes dentro del ejemplo: el borde del margen de la imagen y el marcador vacío.
¿Cuándo hace falta un método distinto?
Insertar un marcador es un diagnóstico y, por tanto, mide el diseño resultante. Añadirlo a un párrafo cualquiera existente puede ofrecer una oportunidad de salto de línea o afectar al diseño de alguna otra manera. Si se cumplen los requisitos previos, es preferible calcularlo a partir de la imagen existente. Si insertas un marcador en contenido real, comprueba que las mismas imágenes sigan en la misma línea y que sus posiciones no hayan cambiado.
| Situación | Siguiente paso adecuado |
|---|---|
Las imágenes usan la alineación top, bottom o middle |
Inspecciona esa regla de alineación; no apliques sin cambios la fórmula para imágenes alineadas por la línea de base |
| La imagen está dentro de un contenedor de bloque en línea | Inspecciona la línea de base del contenedor, que puede provenir de su última línea de contenido |
| Las imágenes ocupan varias líneas ajustadas | Determina una línea de base para cada línea |
| El elemento principal usa un diseño flex o de cuadrícula | Inspecciona las reglas de alineación de ese diseño antes de tratar la fila como una línea en línea |
| El documento usa escritura vertical | Usa las reglas de línea de base que tienen en cuenta el modo de escritura, en lugar de una coordenada y del borde inferior |
| La imagen no se ha cargado correctamente | Resuelve su estado de representación antes de tratarla como una caja de imagen mostrada |
La última condición importa porque WHATWG describe distintas rutas de representación para imágenes mostradas, imágenes pendientes y texto alternativo. Por tanto, una imagen rota que muestra su etiqueta puede requerir una interpretación distinta de la imagen representada correctamente que querías medir. Consulta las reglas de representación de imágenes de HTML.
Evita deducir que varias imágenes comparten una línea de base solo porque sus rectángulos tienen coordenadas superiores parecidas. Imágenes de distintas alturas pueden compartir la línea de base y tener bordes superiores diferentes. A la inversa, que los bordes superiores estén alineados no demuestra que haya alineación por la línea de base. Confirma qué cajas participan en la misma línea y qué regla de alineación se aplica.
¿Pueden las API de medición de texto o las bibliotecas de conformación tipográfica proporcionar la respuesta?
Los métodos de geometría del navegador que se usan aquí devuelven rectángulos, no un campo específico para la línea de base. Range.getClientRects() puede ayudar a inspeccionar las áreas que ocupa un rango, pero los rectángulos que devuelve no proporcionan directamente la coordenada de la línea de base. MDN describe esa interfaz en Range.getClientRects().
Las métricas de texto de Canvas responden a otra pregunta: cómo se relaciona un fragmento de texto de Canvas con la línea de base de texto seleccionada en el contexto de Canvas. Por ejemplo, actualBoundingBoxAscent y actualBoundingBoxDescent describen los límites de la tinta del texto respecto a esa referencia. No localizan directamente una fila de imágenes del DOM existente. Consulta la documentación de TextMetrics de MDN.
Una biblioteca de conformación tipográfica también tiene una responsabilidad más acotada que el diseño de líneas del navegador. El manual de HarfBuzz indica que conforma secuencias de texto y proporciona información sobre la disposición de los glifos, mientras que el salto de línea de párrafo y la justificación quedan fuera de sus responsabilidades. Por tanto, instalar HarfBuzz no proporciona una medición de una línea del navegador formada solo por imágenes. Su alcance documentado ayuda a establecer ese límite.
Para una línea horizontal formada solo por imágenes, primero confirma que estén en el flujo en línea normal y alineadas por la línea de base. Luego, consulta el borde inferior de la caja de borde de una imagen que cumpla las condiciones y súmale su margen inferior. Usa el marcador de tamaño cero en un diseño controlado cuando necesites una verificación visual y vuelve a evaluar el contexto de formato si esas dos referencias no coinciden.
Fuentes
Estándar HTML: representación — WHATWG.
Estándar HTML: el elemento canvas — WHATWG.
Abrir Chrome DevTools — Google Chrome para desarrolladores.
Propiedad CSS vertical-align — MDN Web Docs.
Elemento: método getBoundingClientRect() — MDN Web Docs.
HTMLImageElement: método decode() — MDN Web Docs.
Range: método getClientRects() — MDN Web Docs.
TextMetrics — MDN Web Docs.
Lo que HarfBuzz no hace — HarfBuzz.