Optimización de fuentes e imágenes

En el capítulo anterior, aprendiste cómo estilizar tu aplicación Next.js. Continuemos trabajando en tu página de inicio añadiendo una fuente personalizada y una imagen hero.

¿Por qué optimizar fuentes?

Las fuentes juegan un papel importante en el diseño de un sitio web, pero usar fuentes personalizadas en tu proyecto puede afectar el rendimiento si los archivos de fuente necesitan ser recuperados y cargados.

El Cambio Acumulativo de Diseño (CLS) es una métrica utilizada por Google para evaluar el rendimiento y experiencia de usuario de un sitio web. Con las fuentes, el cambio de diseño ocurre cuando el navegador inicialmente renderiza texto en una fuente de respaldo o del sistema y luego la reemplaza por una fuente personalizada una vez cargada. Este intercambio puede causar que el tamaño del texto, espaciado o diseño cambien, desplazando elementos alrededor.

Mock UI mostrando carga inicial de una página, seguido por un cambio de diseño al cargar la fuente personalizada.

Next.js optimiza automáticamente las fuentes en la aplicación cuando usas el módulo next/font. Descarga los archivos de fuente en tiempo de compilación y los aloja con tus otros activos estáticos. Esto significa que cuando un usuario visita tu aplicación, no hay solicitudes de red adicionales para fuentes que afectarían el rendimiento.

Añadiendo una fuente primaria

Añadamos una fuente Google personalizada a tu aplicación para ver cómo funciona.

En tu carpeta /app/ui, crea un nuevo archivo llamado fonts.ts. Usarás este archivo para mantener las fuentes que se usarán en toda tu aplicación.

Importa la fuente Inter del módulo next/font/google - esta será tu fuente primaria. Luego, especifica qué subconjunto deseas cargar. En este caso, 'latin':

/app/ui/fonts.ts
import { Inter } from 'next/font/google';
 
export const inter = Inter({ subsets: ['latin'] });

Finalmente, añade la fuente al elemento <body> en /app/layout.tsx:

/app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

Al añadir Inter al elemento <body>, la fuente se aplicará en toda tu aplicación. Aquí también añades la clase de Tailwind antialiased que suaviza la fuente. No es necesario usar esta clase, pero añade un buen toque.

Navega a tu navegador, abre las herramientas de desarrollo y selecciona el elemento body. Deberías ver que Inter e Inter_Fallback ahora están aplicados bajo estilos.

Práctica: Añadiendo una fuente secundaria

También puedes añadir fuentes a elementos específicos de tu aplicación.

¡Ahora es tu turno! En tu archivo fonts.ts, importa una fuente secundaria llamada Lusitana y pásala al elemento <p> en tu archivo /app/page.tsx. Además de especificar un subconjunto como hiciste antes, también debes especificar diferentes pesos de fuente. Por ejemplo, 400 (normal) y 700 (negrita).

Una vez listo, expande el snippet de código abajo para ver la solución.

Pistas:

Finalmente, el componente <AcmeLogo /> también usa Lusitana. Estaba comentado para prevenir errores, ahora puedes descomentarlo:

/app/page.tsx
// ...
 
export default function Page() {
  return (
    <main className="flex min-h-screen flex-col p-6">
      <div className="flex h-20 shrink-0 items-end rounded-lg bg-blue-500 p-4 md:h-52">
        <AcmeLogo />
        {/* ... */}
      </div>
    </main>
  );
}

¡Genial, has añadido dos fuentes personalizadas a tu aplicación! A continuación, añadamos una imagen hero a la página de inicio.

¿Por qué optimizar imágenes?

Next.js puede servir activos estáticos, como imágenes, bajo la carpeta de nivel superior /public. Los archivos dentro de /public pueden ser referenciados en tu aplicación.

Con HTML regular, añadirías una imagen así:

<img
  src="/hero.png"
  alt="Capturas del proyecto del dashboard mostrando versión de escritorio"
/>

Sin embargo, esto significa que debes manualmente:

  • Asegurar que tu imagen sea responsive en diferentes tamaños de pantalla.
  • Especificar tamaños de imagen para diferentes dispositivos.
  • Prevenir cambios de diseño mientras las imágenes cargan.
  • Cargar diferidamente imágenes fuera del viewport del usuario.

La Optimización de Imágenes es un tema amplio en desarrollo web que podría considerarse una especialización en sí mismo. En lugar de implementar estas optimizaciones manualmente, puedes usar el componente next/image para optimizar automáticamente tus imágenes.

El componente <Image>

El componente <Image> es una extensión de la etiqueta HTML <img>, y viene con optimización automática de imágenes, como:

  • Prevenir cambios de diseño automáticamente mientras las imágenes cargan.
  • Redimensionar imágenes para evitar enviar imágenes grandes a dispositivos con viewport más pequeño.
  • Carga diferida de imágenes por defecto (las imágenes cargan al entrar al viewport).
  • Servir imágenes en formatos modernos, como WebP y AVIF, cuando el navegador lo soporte.

Añadiendo la imagen hero de escritorio

Usemos el componente <Image>. Si miras dentro de la carpeta /public, verás que hay dos imágenes: hero-desktop.png y hero-mobile.png. Estas dos imágenes son completamente diferentes, y se mostrarán dependiendo si el dispositivo del usuario es escritorio o móvil.

En tu archivo /app/page.tsx, importa el componente de next/image. Luego, añade la imagen bajo el comentario:

/app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Añadir Imágenes Hero Aquí */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Capturas del proyecto del dashboard mostrando versión de escritorio"
      />
    </div>
    //...
  );
}

Aquí, estás configurando el width a 1000 y height a 760 píxeles. Es buena práctica establecer el width y height de tus imágenes para evitar cambios de diseño, estos deben tener una relación de aspecto idéntica a la imagen fuente. Estos valores no son el tamaño en que se renderiza la imagen, sino el tamaño del archivo de imagen real usado para entender la relación de aspecto.

También notarás la clase hidden para remover la imagen del DOM en pantallas móviles, y md:block para mostrar la imagen en pantallas de escritorio.

Así debería verse ahora tu página de inicio:

Página de inicio estilizada con fuente personalizada e imagen hero

Práctica: Añadiendo la imagen hero móvil

¡Ahora es tu turno! Bajo la imagen que acabas de añadir, añade otro componente <Image> para hero-mobile.png.

  • La imagen debe tener un width de 560 y height de 620 píxeles.
  • Debe mostrarse en pantallas móviles, y ocultarse en escritorio - puedes usar herramientas de desarrollo para verificar si las imágenes de escritorio y móvil se intercambian correctamente.

Una vez listo, expande el snippet de código abajo para ver la solución.

¡Genial! Tu página de inicio ahora tiene una fuente personalizada e imágenes hero.

Lectura recomendada

Hay mucho más por aprender sobre estos temas, incluyendo optimización de imágenes remotas y uso de archivos de fuentes locales. Si deseas profundizar en fuentes e imágenes, consulta:

On this page