ProseImg
Una imagen: consciente del tema, adaptable y ampliable.
Cada imagen de una página Markdown.
Cada ejemplo de abajo es un bloque de código. Las imágenes de prueba son ese mismo marcado realmente dibujado: un gemelo oscuro, un original más estrecho que la columna, un vector, una animación y una imagen que se niega a ampliarse.
Qué añade
Dos variantes. Una captura de un editor oscuro sobre una página blanca — o al revés — es la fealdad más común de una documentación, y CSS no puede arreglarla porque lo que está mal son los píxeles, no el marco. Una página puede nombrar un segundo archivo:
{dark="/shots/sidebar-dark.png"}
Dos peticiones, no un archivo. La imagen de la página y la del diálogo de
zoom piden anchos distintos, así que un teléfono ya no descarga el original de
2400 px para dibujarlo en una columna de 48rem. Ambas son srcset generados por
@nuxt/image; ninguna es un archivo que alguien deba preparar.
Clic para ampliar, salvo que la imagen pida lo contrario:
{zoom="false"}
Una imagen ampliable lleva un pequeño indicador de zoom en su esquina, de forma
permanente y no al pasar el cursor — un cursor no existe en un dispositivo táctil
y es invisible en una captura de la página. La imagen es un botón: Tab lo
alcanza con un anillo visible, Enter y Espacio abren el diálogo, Escape lo
cierra y devuelve el foco. Con zoom="false" no hay indicador, ni anillo, ni
nada a lo que tabular.
Un fondo para una imagen transparente. Un diagrama cuyo trazo está pensado
para una superficie clara desaparece en una página oscura. Indica un color por
tema — cualquier color CSS, var(--card) incluido:
{background="#fafafa" dark-background="#171717"}
Colores y no clases, a propósito: la hoja de estilos de la capa se genera a partir
de sus propios componentes, nunca del Markdown, así que una clase dark:bg-…
escrita en una página no tendría CSS detrás.
El visor ocupa toda la pantalla sobre la página desenfocada. Sus controles —
alejar, el nivel de zoom (que lo restablece), acercar, abrir el original en una
pestaña nueva, cerrar — flotan en una fila sobre la imagen y el texto alternativo
va debajo, de modo que ninguno la tapa. La rueda amplía alrededor del cursor y
el gesto de pinza alrededor de los dedos; un clic en la imagen la amplía al 200 %
en ese punto y un segundo clic vuelve; +, - y 0 hacen lo mismo desde el
teclado. Una imagen ampliada se arrastra para desplazarla y carga el archivo
original para seguir nítida. Un clic en el espacio alrededor cierra el visor.
API
Props
| Prop | Tipo | Por defecto | Notas |
|---|---|---|---|
src | string | — | Tal cual se escribe |
alt | string | — | Tal cual se escribe |
dark | string | — | Un segundo archivo, servido bajo el tema oscuro |
zoom | boolean | true | false deja la imagen inerte |
width | number | — | Opcional; véase Dimensiones más abajo |
height | number | — | Opcional; véase Dimensiones más abajo |
sizes | string | — | Sustituye la política de la página; véase Tamaños |
background | string | — | Un color CSS detrás de una imagen transparente, en la página y en el visor |
dark-background | string | — | Lo mismo con el tema oscuro; recurre a background |
Tamaños
El tema sabe una cosa que @nuxt/image no puede saber: cuál es el ancho de la
caja en la que dibuja una imagen. Eso es todo lo que configura.
- En la página —
sm:95vw md:768px. Por debajo demdel artículo es el viewport menos sus márgenes; a partir demdqueda limitado amax-w-3xlsea cual sea la pantalla, de modo que el ancho pedido deja de crecer en lugar de seguir subiendo en una pantalla 4K. - En el diálogo —
sm:96vw md:96vw lg:96vw xl:1264px, siguiendo al viewport hasta el propio límite del diálogo,min(96vw, 80rem).
Ambas nombran solo los breakpoints que @nuxt/image ya trae, así que quien
redefina image.screens conserva su definición. La capa no declara screens
propios.
Una imagen que no es tan ancha como la columna de texto — un logotipo, una insignia, un diagrama al margen — lo dice:
{sizes="sm:50vw md:200px"}
sizes es la sintaxis propia de @nuxt/image y alcanza solo a la imagen de la
página. El diálogo conserva su política: una que describe la columna de texto no
puede describir un diálogo.
Dimensiones
width y height son opcionales y lo seguirán siendo — la mayoría de las
páginas las omiten, y exigirlas rompería todas las ya escritas.
Indícalas de todos modos cuando puedas. Son lo que permite al navegador reservar la caja antes de que llegue el archivo; sin ellas la imagen no tiene proporción intrínseca hasta que carga, y el texto de debajo se mueve cuando lo hace. El componente conserva la proporción del par que recibe y no inventa nada cuando no recibe ninguno: no hay proporción por defecto ni recorte, porque una proporción equivocada es peor que un salto.
Una imagen más pequeña que la columna se deja a su propio tamaño en lugar de estirarse.
Formatos
SVG y GIF animado se pasan sin tocar, en la página y en el diálogo, sin
srcset alguno. Un vector no tiene píxeles que remuestrear — pedir uno de 608 px
de ancho rasteriza un archivo que era nítido a cualquier tamaño — y un GIF que
pasa por una tubería de rasterizado vuelve convertido en su primer fotograma.
Esto es lo que hace el componente, no una afirmación sobre los proveedores: algunos pasan estos formatos sin tocarlos y otros no, y una capa de documentación no puede saber cuál ha configurado su consumidor. Las fuentes adaptables son para los formatos de trama para los que existe el zoom — PNG, JPEG, WebP, AVIF.
Proveedores
La capa no establece ninguna clave image. Qué servicio transforma una
imagen es del consumidor, igual que sources: un proveedor elegido por la capa
es un proveedor que todo consumidor tiene que deshacer, y decide una cuenta y una
factura tanto como una URL. Configura
@nuxt/image como en
cualquier aplicación Nuxt; el componente solo le entrega dos cadenas sizes.
A su aire, @nuxt/image elige por sí mismo, y los tres casos con los que se
encuentra un sitio de documentación son:
- Un servidor Node.
ipxtransforma bajo demanda en/_ipx/…. Necesitasharp, un binding nativo, que la salida de Node ya lleva. - Un sitio generado (
nuxt generate).ipxStaticescribe cada variante en tiempo de compilación. Después no corre nada, y la salida crece por las variantes — el trato que un sitio totalmente estático ya está haciendo. - Un entorno de ejecución en el borde — Cloudflare Workers y cualquier otro
que no sea Node ni estático. No corre ningún transformador y las imágenes se
sirven tal como se subieron. Un sitio prerrenderizado en un entorno así no
debe configurarse con
ipx: es un binding nativo y allí no puede ejecutarse en absoluto. Recurre a un proveedor CDN si quieres las transformaciones.
Las variantes del diálogo se generan en una compilación estática aunque el diálogo esté cerrado cuando se renderiza la página — el componente las registra él mismo ante el rastreador de prerrenderizado. No se descarga nada hasta que el diálogo se abre.
Una imagen con zoom="false" no recibe ninguna. No hay diálogo que abrir, así
que cada archivo de tamaño de diálogo escrito para ella sería salida que nadie
puede pedir.
Notas
La variante oscura se nombra explícitamente en lugar de adivinarse por
convención. Derivar -dark de un nombre de archivo significa que un archivo que
falta se convierte en una imagen rota, y el autor nunca se entera.
Una imagen de una fuente clonada desde otro repositorio no tiene ruta propia:
Content descarga el árbol en .data/content/ y nada copia sus recursos a
public/. Las rutas de estos ejemplos son absolutas hacia el propio public/
del sitio consumidor, que es donde una imagen de documentación tiene que vivir
hoy.