Introducción
Un portafolio de diseño son, sobre todo, imágenes. Astro las convierte a WebP, les pone el tamaño y la carga diferida, y te deja añadir interacción solo donde hace falta. Esta página parte del portafolio de las dos anteriores.
Un portafolio de diseño son, sobre todo, imágenes.
Las imágenes de src/ se importan y se pintan con <Image /> o <Picture />: WebP o AVIF, tamaño justo y sin saltos.
Un <script> en un componente es JavaScript para el navegador y se incluye una sola vez.
Las directivas client: convierten un componente de React, Vue o Svelte en una isla interactiva.
<ClientRouter /> y transition:name animan el cambio de página; astro:page-load repite los scripts.
Un portafolio de diseño son, sobre todo, imágenes. Astro las convierte a WebP, les pone el tamaño y la carga diferida, y te deja añadir interacción solo donde hace falta. Esta página parte del portafolio de las dos anteriores.
DóndeQué hace AstroPara src/assets/ (o cualquier carpeta de src/)La optimiza: formato, tamaño, width y heightFotos y portadas de proyectos public/Nada: la copia tal cualFavicon, imágenes para redes, ficheros que no se tocan
Las de src/ se importan y se pintan con el componente <Image />:
--- import { Image } from 'astro:assets'; import retrato from '../assets/retrato-lucia.jpg'; --- <Image src={retrato} alt="Lucía Prieto en su estudio, delante de un tablero de bocetos" width={480} />
El HTML que genera:
Lo que va entre --- se ejecuta al construir. Para que algo pase en el navegador (un botón, un menú que se abre), un <script> en el componente:
--- // src/components/BotonTema.astro --- <button type="button" class="boton-tema" aria-pressed="false">Modo oscuro</button> <script> const boton = document.querySelector('.boton-tema'); boton?.addEventListener('click', () => { const oscuro = document.documentElement.classList.toggle('oscuro'); boton.setAttribute('aria-pressed', String(oscuro)); }); </script>
Astro junta estos scripts, los optimiza y los incluye una sola vez, aunque uses el componente en diez sitios. Es JavaScript normal, el mismo que usas con el DOM y los eventos.
Si necesitas un componente hecho con React, Vue, Svelte o Preact (un configurador, un mapa), Astro lo pinta como HTML sin JavaScript. Para que funcione en el navegador, le pones una directiva client: y ese componente pasa a ser una isla: una parte interactiva dentro de una página estática.
DirectivaCuándo carga su JavaScript client:loadNada más abrir la página. Para lo que se usa enseguida client:idleCuando el navegador termina lo más urgente client:visibleCuando el componente aparece en pantalla al bajar client:media="(max-width: 50em)"Solo si se cumple la media query client:only="react"Solo en el navegador; no se genera HTML al construir
--- // Antes: npx astro add react import Configurador from '../components/Configurador.jsx'; --- <Configurador client:visible />
Sin directiva no hay JavaScript. Es la idea de Astro: la página llega como HTML y solo se carga el código de las partes que lo necesitan. Para un botón o un menú, el <script> de arriba basta: no hace falta un framework.
Con <ClientRouter /> en el <head> del layout, Astro cambia de página sin recargarla entera y anima el cambio (un fundido, por defecto):
--- // src/layouts/Base.astro import { ClientRouter } from 'astro:transitions'; --- <head> <!-- … --> <ClientRouter /> </head>
Para que la portada de la tarjeta «vuele» hasta su sitio en la página del proyecto, dale el mismo transition:name en las dos páginas:
<!-- En la tarjeta (portada) --> <Image src={portada} alt={textoAlternativo} width={600} transition:name={`portada-${proyecto.id}`} /> <!-- En la página del proyecto --> <Image src={proyecto.data.portada} alt={proyecto.data.textoAlternativo} width={1200} transition:name={`portada-${proyecto.id}`} />
Pon las portadas de tus proyectos en src/assets/ y añade portada: image() al esquema. Pinta la portada con <Image /> en la tarjeta (width={600}) y en la página del proyecto (width={1200}). Mira en las DevTools, pestaña Red, qué formato y qué peso llegan. Añade <ClientRouter /> al layout y el mismo transition:name a las dos imágenes. Crea BotonTema.astro con su <script> y comprueba que sigue funcionando después de cambiar de página (si no, usa astro:page-load).
Poner las fotos en public/ y usar <img>: llegan a tamaño original, sin WebP y sin width ni height. Olvidar alt en <Image />: es un error al construir. Poner client:load a todo: se pierde la ventaja de Astro. Elige client:visible o client:idle si no corre prisa. Repetir el mismo transition:name en dos elementos de la misma página. Seguir un tutorial con <ViewTransitions />: desde Astro 6 se llama <ClientRouter />.
Un portafolio de diseño son, sobre todo, imágenes.
Código del tema: <ClientRouter />
Un portafolio de diseño son, sobre todo, imágenes. Astro las convierte a WebP, les pone el tamaño y la carga diferida, y te deja añadir interacción solo donde hace falta. Esta página parte del portafolio de las dos anteriores.
| Dónde | Qué hace Astro | Para |
|---|---|---|
src/assets/ (o cualquier carpeta de src/) | La optimiza: formato, tamaño, width y height | Fotos y portadas de proyectos |
public/ | Nada: la copia tal cual | Favicon, imágenes para redes, ficheros que no se tocan |
Las de src/ se importan y se pintan con el componente <Image />:
---
import { Image } from 'astro:assets';
import retrato from '../assets/retrato-lucia.jpg';
---
<Image src={retrato} alt="Lucía Prieto en su estudio, delante de un tablero de bocetos" width={480} />El HTML que genera:
<img src="/_astro/retrato-lucia.B7x2.webp" alt="Lucía Prieto en su estudio…"
width="480" height="600" loading="lazy" decoding="async">width y height: el navegador reserva el hueco y la página no salta al cargar.alt es obligatorio. Si la imagen es decorativa, alt="".loading="lazy": las imágenes que están más abajo se cargan al acercarte. Para la imagen grande de arriba del todo, pon loading="eager".En las colecciones, image() en el esquema (página anterior) hace que proyecto.data.portada sea una imagen lista para <Image />:
<Image src={proyecto.data.portada} alt={proyecto.data.textoAlternativo} width={1200} />Para ofrecer varios formatos (AVIF, que pesa menos, y WebP para el resto), <Picture />:
---
import { Picture } from 'astro:assets';
import cartel from '../assets/cartel-jazz.png';
---
<Picture src={cartel} formats={['avif', 'webp']} alt="Cartel del festival Jazz en la Alameda" width={800} />En Markdown, las imágenes con ruta relativa también se optimizan: !Boceto del cartel. Con ruta desde / (/imagenes/boceto.jpg) salen de public/ y no se tocan.
Lo que va entre --- se ejecuta al construir. Para que algo pase en el navegador (un botón, un menú que se abre), un <script> en el componente:
---
// src/components/BotonTema.astro
---
<button type="button" class="boton-tema" aria-pressed="false">Modo oscuro</button>
<script>
const boton = document.querySelector('.boton-tema');
boton?.addEventListener('click', () => {
const oscuro = document.documentElement.classList.toggle('oscuro');
boton.setAttribute('aria-pressed', String(oscuro));
});
</script>Astro junta estos scripts, los optimiza y los incluye una sola vez, aunque uses el componente en diez sitios. Es JavaScript normal, el mismo que usas con el DOM y los eventos.
Si necesitas un componente hecho con React, Vue, Svelte o Preact (un configurador, un mapa), Astro lo pinta como HTML sin JavaScript. Para que funcione en el navegador, le pones una directiva client: y ese componente pasa a ser una isla: una parte interactiva dentro de una página estática.
| Directiva | Cuándo carga su JavaScript |
|---|---|
client:load | Nada más abrir la página. Para lo que se usa enseguida |
client:idle | Cuando el navegador termina lo más urgente |
client:visible | Cuando el componente aparece en pantalla al bajar |
client:media="(max-width: 50em)" | Solo si se cumple la media query |
client:only="react" | Solo en el navegador; no se genera HTML al construir |
---
// Antes: npx astro add react
import Configurador from '../components/Configurador.jsx';
---
<Configurador client:visible />Sin directiva no hay JavaScript. Es la idea de Astro: la página llega como HTML y solo se carga el código de las partes que lo necesitan. Para un botón o un menú, el <script> de arriba basta: no hace falta un framework.
Con <ClientRouter /> en el <head> del layout, Astro cambia de página sin recargarla entera y anima el cambio (un fundido, por defecto):
---
// src/layouts/Base.astro
import { ClientRouter } from 'astro:transitions';
---
<head>
<!-- … -->
<ClientRouter />
</head>Para que la portada de la tarjeta «vuele» hasta su sitio en la página del proyecto, dale el mismo transition:name en las dos páginas:
<!-- En la tarjeta (portada) -->
<Image src={portada} alt={textoAlternativo} width={600} transition:name={`portada-${proyecto.id}`} />
<!-- En la página del proyecto -->
<Image src={proyecto.data.portada} alt={proyecto.data.textoAlternativo} width={1200}
transition:name={`portada-${proyecto.id}`} />Cada nombre solo puede aparecer una vez en cada página; por eso lleva el id del proyecto. Otras opciones: transition:animate="slide" (o "none") y transition:persist, que mantiene un elemento sin cambiar entre páginas (un reproductor de audio, por ejemplo).
Con <ClientRouter /> la página no se recarga, así que un <script> se ejecuta solo la primera vez. Si tiene que preparar algo en cada página, mételo en el evento astro:page-load:
document.addEventListener('astro:page-load', () => {
const boton = document.querySelector('.boton-tema');
// … lo mismo que antes
});El navegador respeta la preferencia de «reducir el movimiento» del sistema: con ella activada, Astro no anima.
src/assets/ y añade portada: image() al esquema.<Image /> en la tarjeta (width={600}) y en la página del proyecto (width={1200}). Mira en las DevTools, pestaña Red, qué formato y qué peso llegan.<ClientRouter /> al layout y el mismo transition:name a las dos imágenes.BotonTema.astro con su <script> y comprueba que sigue funcionando después de cambiar de página (si no, usa astro:page-load).public/ y usar <img>: llegan a tamaño original, sin WebP y sin width ni height.alt en <Image />: es un error al construir.client:load a todo: se pierde la ventaja de Astro. Elige client:visible o client:idle si no corre prisa.transition:name en dos elementos de la misma página.<ViewTransitions />: desde Astro 6 se llama <ClientRouter />.