Implementa el modo oscuro en tu sitio web con Astro y View Transitions

AstroView TransitionsTailwind
Publicado el 12/13/2024
Fecha de ultima actualización: 12/13/2024

En sitios web con navegación SPA (Single Page Application), como los creados con Astro, es común enfrentarse a problemas al manejar temas entre páginas, especialmente cuando se busca mantener una experiencia fluida. Uno de los problemas más frecuentes es que los event listeners pueden perderse al navegar entre páginas, lo que afecta la funcionalidad de elementos como botones. Aquí veremos una solución que combina inicialización del tema, almacenamiento de preferencias y sincronización con View Transitions.

Paso 1: Inicialización del tema

El primer paso para implementar el modo oscuro es detectar y aplicar las preferencias del usuario. Esto incluye leer de localStorage y, si no hay un valor guardado, usar la preferencia del sistema.

const applyTheme = (isDark) => {
document.documentElement.classList.toggle('dark', isDark);
document.documentElement.setAttribute('data-theme', isDark ? 'github-dark-default' : 'github-light-default');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
};
const getThemePreference = () => {
return localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
};
const initializeTheme = () => {
const isDark = getThemePreference() === 'dark';
applyTheme(isDark);
};
initializeTheme();
  • getThemePreference: Determina la preferencia del usuario basándose en localStorage o en el esquema de colores del sistema.
  • applyTheme: Aplica la clase dark al elemento html y actualiza el atributo data-theme. También guarda la preferencia en localStorage.

Con esto aseguramos que el sitio respete la preferencia del usuario al cargar.

Parpadeo al cargar la página: Esto se resolvió inicializando el tema lo antes posible en el script para evitar el estilo predeterminado.

Paso 2: Agregar el toggle para cambiar el tema

El siguiente paso es crear un botón que permita alternar entre modo claro y oscuro de forma interactiva. Este botón debe funcionar correctamente incluso tras navegar entre páginas.

const attachThemeToggle = () => {
const toggleButton = document.getElementById('theme-toggle');
if (!toggleButton) return;
toggleButton.addEventListener('click', () => {
const isDark = !document.documentElement.classList.contains('dark');
applyTheme(isDark);
});
};
attachThemeToggle();
  • attachThemeToggle: Busca el botón por su ID y asocia un evento click que alterna entre los modos claro y oscuro.

Este paso asegura que los usuarios puedan cambiar el tema manualmente.

Paso 3: Sincronización con transiciones de vista

Uno de los retos más grandes fue garantizar que el botón siga funcionando tras navegar entre páginas, ya que Astro reemplaza el DOM durante las transiciones. Esto lo resolvemos utilizando el evento astro:after-swap.

document.addEventListener('astro:after-swap', () => {
// Asegurar que el tema se aplique en el nuevo documento
initializeTheme();
// Reasociar el evento al nuevo botón
attachThemeToggle();
});
  • astro:after-swap: Este evento se dispara después de que Astro actualiza el DOM al navegar. Aquí volvemos a aplicar el tema y asociar el evento del botón al nuevo documento.

Botón que deja de funcionar tras navegar: Usamos astro:after-swap para reasociar el evento en el nuevo DOM.

Dónde insertar el código

Para garantizar que el código funcione correctamente, debes insertarlo a nivel del layout principal de tu proyecto Astro. Todo el script debe estar contenido dentro de un <script is:inline> como se muestra en el siguiente ejemplo.

Layout.astro
<script is:inline>
// Código completo
</script>

Conclusión

Con estos pasos, puedes agregar un modo oscuro funcional y sincronizado a tu sitio web con Astro. Esta implementación respeta las preferencias del usuario, permite alternar entre temas y soluciona problemas comunes como la pérdida de eventos con View Transitions.