Cómo conservar el estado del menú al cargar la página (usando almacenamiento local)
() translation by (you can also view the original English article)



En este tutorial, crearemos un sitio estático simple con Tailwind CSS y luego aprenderemos cómo conservar el estado de su menú al cargar la página.
La primera vez que visitemos el sitio, el menú estará oculto. Sin embargo, tan pronto como lo abramos y cerremos el navegador, utilizaremos almacenamiento local y JavaScript para mantener el menú abierto la próxima vez que visitemos el sitio. De hecho, permanecerá abierto hasta que lo volvamos a cerrar.
¿Estás listo para otro desafío?
1. Crea el proyecto
Como primer paso, tenemos que configurar la estructura del proyecto y decidir dónde lo alojaremos.
Una opción es desarrollarlo de manera local y después, una vez que esté listo, subirlo a GitHub Pages. He utilizado este método anteriormente para diferentes demostraciones. Por ejemplo, échale un vistazo a esta donde se personaliza las pestañas de Bootstrap 4.
Un método alternativo es usar CodePen Projects tanto para el desarrollo como para el alojamiento. Cabe señalar que, según tu plan de CodePen, podrás alojar una cantidad diferente de proyectos.
Para este tutorial, como no lo hemos hecho antes, vamos a crear un proyecto en CodePen y vamos a aprovechar todas las potentes funciones que lo acompañan.



De manera predeterminada, CodePen ofrece varias plantillas de proyectos iniciales. Aquí, seleccionaremos la más básica.



Nuestro proyecto incluirá cuatro archivos HTML similares, un archivo SCSS que se compilará en un CSS y un archivo JavaScript, como este:



Y por último, aunque no por ello menos importante, podrás exportarlo y ejecutarlo desde tu máquina local.



2. Tailwind CSS
En vez de crear los estilos desde cero, vamos a usar Tailwind CSS, un nuevo y popular framework de CSS con un enfoque «utility-first» y que ha ganado mucho terreno con los desarrolladores. Fue creado por Adam Wathan, su filosofía es mover toda la complejidad a los archivos HTML añadiendo clases preexistentes a los elementos.



Como siempre me gustó este concepto, lo he seguido en el pasado para algunas demostraciones como esta. Aprende más aquí:
3. El HTML
Todos los archivos HTML contendrán una cabecera y algo de contenido ficticio.
Dentro de la cabecera colocaremos:
- El logotipo de la empresa
- El ícono de hamburguesa
- El menú de navegación
También necesitaremos incluir los siguientes archivos:
- El archivo de CSS Tailwind
- Nuestros propios archivos de CSS y JavaScript
Para hacer que el ícono de hamburguesa sea un poco más accesible, usaremos los atributos ARIA: aria-label
, aria-extended
y aria-controls
. Como veremos más adelante, los valores de los dos primeros atributos cambiarán según el estado del menú.
Este es el marcado para la página index.html
:
1 |
<!DOCTYPE html>
|
2 |
<html lang="en"> |
3 |
<head>
|
4 |
<!-- Meta -->
|
5 |
<meta charset="UTF-8"> |
6 |
<title>Home Page</title> |
7 |
<meta name="viewport" content="width=device-width, initial-scale=1"> |
8 |
|
9 |
<!-- Styles -->
|
10 |
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"> |
11 |
<link rel="stylesheet" href="styles/index.processed.css"> |
12 |
</head>
|
13 |
|
14 |
<body class="text-lg"> |
15 |
<header class="sticky top-0 bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 p-5 shadow-xl"> |
16 |
<nav>
|
17 |
<div class="flex items-center justify-between"> |
18 |
<a href="index.html"> |
19 |
<img width="178" height="38" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/horizontal-logo.svg" alt="forecastr logo"> |
20 |
</a>
|
21 |
<button class="toggle-button grid gap-y-2.5 focus:outline-none" type="button" aria-controls="menu" aria-label="Open navigation" aria-expanded="false"> |
22 |
<span class="bg-white w-10 h-1 transition-transform"></span> |
23 |
<span class="bg-white w-10 h-1"></span> |
24 |
<span class="bg-white w-10 h-1 transition-transform"></span> |
25 |
</button>
|
26 |
</div>
|
27 |
<div class="absolute right-0 top-full mt-4 mr-3 overflow-y-hidden"> |
28 |
<ul id="menu" class="menu flex transition-transform transform translate-y-full"> |
29 |
<li class="mr-6"> |
30 |
<a href="about.html" class="inline-block font-semibold text-gray-400 hover:text-gray-900 transition-colors duration-300 p-2">About</a> |
31 |
</li>
|
32 |
<li class="mr-6"> |
33 |
<a href="clients.html" class="inline-block font-semibold text-gray-400 hover:text-gray-900 transition-colors duration-300 p-2">Clients</a> |
34 |
</li>
|
35 |
<li>
|
36 |
<a href="contact.html" class="inline-block font-semibold text-gray-400 hover:text-gray-900 transition-colors duration-300 p-2">Contact</a> |
37 |
</li>
|
38 |
</ul>
|
39 |
</div>
|
40 |
</nav>
|
41 |
</header>
|
42 |
|
43 |
<main class="my-20"> |
44 |
<section>
|
45 |
<div class="container max-w-5xl px-8 mx-auto"> |
46 |
<h1 class="font-bold text-5xl mb-8">Home Page</h1> |
47 |
<p class="mb-5"...</p> |
48 |
... |
49 |
<a href="" class="inline-block bg-red-500 hover:bg-red-600 text-white font-semibold py-2 px-4 rounded-lg shadow-md" target="_blank">Read article</a> |
50 |
</div>
|
51 |
</section>
|
52 |
<!-- more sections here -->
|
53 |
</main>
|
54 |
|
55 |
<!-- Scripts -->
|
56 |
<script src="scripts/index.js"></script> |
57 |
</body>
|
58 |
</html>
|
No te sientas abrumado por la cantidad de clases auxiliares de CSS. Todas estas provienen de Tailwind CSS (además de toggle-button
y menu
que usaremos en la parte de JavaScript para hacer referencia a los elementos objetivo).
Como este no es un tutorial sobre Tailwind, no voy a explicar lo que hace cada clase. La mayoría de ellas se explican por sí mismas, pero hay otras como text-5xl
que no son tan claras, por lo que tendrás que buscar en la documentación o en la consola del navegador y ver su uso exacto.
Solo para darte una idea, considera las clases que aplicamos al elemento .menu
junto con el CSS generado:
Clase de utilidad | CSS generado |
flex | display: flex; |
transition-transform | transition-property: transform; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms |
transform | --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); |
translate-y-full | --tw-translate-y: 100%; |
4. Alternar el menú
Cada vez que hagamos clic en el enlace del menú, ocurrirán las siguientes acciones:
- Cambiaremos su clase
is-active
. Si contiene esta clase, se tranformará suavemente en un ícono menos. - Cambiaremos la clase
translate-y-full
del menú. Esta es una clase de Tailwind que determinará si el menú aparecerá o no. - Dependiendo del estado del menú, actualizaremos los atributos
aria-label
yaria-expanded
de ARIA.
Este es el código JavaScript que implementará esta funcionalidad:
1 |
const toggleButton = document.querySelector(".toggle-button"); |
2 |
const menu = document.querySelector(".menu"); |
3 |
const activeClass = "is-active"; |
4 |
const hiddenClass = "translate-y-full"; |
5 |
|
6 |
toggleButton.addEventListener("click", function() { |
7 |
this.classList.toggle(activeClass); |
8 |
menu.classList.toggle(hiddenClass); |
9 |
if (menu.classList.contains(hiddenClass)) { |
10 |
this.setAttribute("aria-label", "Open navigation"); |
11 |
this.setAttribute("aria-expanded", "false"); |
12 |
} else { |
13 |
this.setAttribute("aria-label", "Close navigation"); |
14 |
this.setAttribute("aria-expanded", "true"); |
15 |
}
|
16 |
});
|
Y los estilos SCSS relacionados:
1 |
.toggle-button { |
2 |
&.is-active { |
3 |
span { |
4 |
&:first-child { |
5 |
transform: translateY(14px); |
6 |
}
|
7 |
|
8 |
&:last-child { |
9 |
transform: translateY(-14px); |
10 |
}
|
11 |
}
|
12 |
}
|
13 |
}
|
Conservar el estado del menú al cargar la página
Hasta el momento, nuestro menú funciona muy bien. Pero vayamos un paso más allá y aprendamos cómo preservar su estado. Dicho lo cual, la primera vez que visitemos el sitio, el menú será invisible. Sin embargo, tan pronto como lo abramos y cerremos el navegador, este permanecerá abierto la próxima vez que visitemos el sitio hasta que lo volvamos a cerrar.
Este es un caso perfecto para mostrar cómo el almacenamiento local puede resolver este tipo de solicitud.
Seamos más específicos:
- Tras hacer clic en el ícono de hamburguesa, guardaremos en el almacenamiento local la clave
menu-state
. Los valores posibles pueden seropen
yclosed
.



- Cuando la página se cargue, comprobaremos el valor de esta clave. Si el usuario ya ha abierto el menú, el ícono de hamburguesa recibirá la clase
is-active
, el menú no contendrá la clasetranslate-y-full
y los atributos relacionados con ARIA cambiarán en consecuencia.



Veamos el código JavaScript que controlará esta lógica:
1 |
...
|
2 |
|
3 |
if (localStorage.getItem("menu-state") === "open") { |
4 |
toggleButton.classList.add(activeClass); |
5 |
menu.classList.remove(hiddenClass); |
6 |
toggleButton.setAttribute("aria-label", "Close navigation"); |
7 |
toggleButton.setAttribute("aria-expanded", "true"); |
8 |
}
|
9 |
|
10 |
toggleButton.addEventListener("click", function() { |
11 |
if (menu.classList.contains(hiddenClass)) { |
12 |
localStorage.setItem("menu-state", "closed"); |
13 |
} else { |
14 |
localStorage.setItem("menu-state", "open"); |
15 |
}
|
16 |
});
|
Naturalmente, como mejora, puedes evitar que las animaciones se ejecuten al cargar la página. Pero dejaré esto por ahora, ya que su importancia es secundaria.
¡Has aprendido cómo usar el almacenamiento local!
¡Hemos terminado, amigos! Hoy, aprendimos a crear un proyecto de CodePen utilizando Tailwind CSS para sus estilos y manteniendo el estado de su menú al cargar la página con JavaScript y almacenamiento local. Espero que hayas aprendido una o dos cosas nuevas y que pronto puedas aplicarlas en tus proyectos.
No dudes en mejorar la demostración haciendo que el menú sea aún más accesible o añadiendo más funciones de Tailwind. De ser así, ¡no olvides compartirlo con nosotros!
Como Tailwind es un tema de moda en este momento, planeo escribir un tutorial orientado a Tailwind que describirá cómo personalizar sus opciones predeterminadas o combinarlo con otro framework popular como Bootstrap. Si quieres algo específico como esto, háznoslo saber a través de las redes sociales.
¡Como siempre, gracias por leer!
Más proyectos de JavaScript prácticos
Tenemos bastantes tutoriales interesantes de JavaScript que te ayudarán a aprender. ¡Adelante!
- Eventos de desplazamientoCómo animar durante el desplazamiento con JavaScript puroJemima Abu
- DashboardCreando el diseño de un panel de administración con CSS y un toque de JavaScriptGeorge Martsoukos
- HTMLCrea una aplicación meteorológica simple con JavaScript puroGeorge Martsoukos
- JavaScriptCómo implementar un desplazamiento suave con JavaScript puroGeorge Martsoukos