En este codelab, aprenderás a compilar un componente de diseño de navegación lateral desplegable adaptable en la Web. Compilaremos el componente a medida que avancemos, comenzando con HTML, luego CSS y, por último, JavaScript.
Consulta mi entrada de blog Cómo crear un componente de barra de navegación lateral para obtener información sobre las funciones de la plataforma web de CSS que se eligieron para crear este componente.
Configuración
- Haz clic en Remix to Edit para que el proyecto se pueda editar.
- Abre
app/index.html
.
HTML
Primero, obtén los conceptos básicos de la configuración de HTML para que haya contenido y algunos cuadros con los que trabajar.
Coloca el siguiente código HTML en la etiqueta <body>
.
<aside></aside>
<main></main>
El <aside>
contiene el menú de navegación como un elemento complementario de <main>
, que contiene el contenido principal de la página.
A continuación, completaremos esos elementos semánticos con el resto del contenido de la página.
Agrega un elemento de navegación, algunos vínculos de navegación y un vínculo de cierre dentro del elemento <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
Los vínculos se ven muy bien dentro de los elementos <nav>
, y los elementos <nav>
se ven muy bien en las barras laterales <aside>
.
Aun así, podemos hacer más para mejorar.
En el elemento de contenido principal, agrega un encabezado y un artículo para contener semánticamente el contenido del diseño.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
El encabezado tiene el vínculo para abrir el menú. El aside tiene el botón de cierre. Pronto mostraremos y ocultaremos elementos según el tamaño de la ventana gráfica.
En el elemento <article>
, pegamos una oración de marcador de posición. Reemplaza `` con tu propio contenido o pega el texto de Lorem que se proporciona a continuación:
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
Este contenido, y su longitud, son los que harán que la página se pueda desplazar cuando supere la altura del viewport.
Hasta ahora, agregaste un elemento aside, con una nav, vínculos y una forma de cerrar la nav lateral. También agregaste un encabezado, una forma de abrir la navegación lateral y un artículo al elemento principal. Ya es limpio, semántico y bastante atemporal, pero podemos hacerlo más limpio y claro para todos. El vínculo para abrir en la barra lateral podría estar marcado con mayor claridad.
Agrega los atributos title
y aria-label
al elemento de vínculo abierto del encabezado:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
El ícono de SVG abierto también podría marcarse con mayor claridad. Agrega los siguientes atributos al SVG dentro del elemento de vínculo abierto:
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
El vínculo de cierre en la navegación lateral podría estar marcado con mayor claridad.
Agrega los atributos title
y aria-label
al elemento de vínculo de cierre de la navegación lateral:
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
Es hora de diseñar los elementos. El contenido principal y la navegación lateral son elementos secundarios directos de la etiqueta <body>
, por lo que es un buen punto de partida.
Agrega el siguiente código CSS en css/sidenav.css
para que el elemento <body>
diseñe los elementos secundarios.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
Básicamente, este diseño indica que se cree una fila con nombre stack
que contenga todo, y 2 columnas en esa fila, la segunda de las cuales también se llama stack
. La 1ª columna debe tener el tamaño según las necesidades mínimas de contenido, y la 2ª columna puede ocupar el resto.
Luego, si se encuentra en una ventana gráfica restringida de 540px
o menos, coloca los elementos de la navegación lateral y el contenido principal en la misma fila y columna, lo que hará que se superpongan en una cuadrícula de 1x1.
Con esta funcionalidad de apilamiento adaptable como base, ahora podemos aprovechar el estado de la barra de URL para activar o desactivar la visibilidad y el estilo de transición de la navegación lateral.
Actualiza el elemento <aside>
en app/index.html
:
<aside>
<aside id="sidenav-open">
Esto permite que el CSS coincida con un elemento y el hash de URL. Esto es importante para el uso de :target
.
Ahora, el ID del elemento puede coincidir con el hash de URL que estableceremos con las etiquetas <a>
.
Además, para facilitar la segmentación de JavaScript, agrega IDs a los elementos clave que controlan la navegación lateral. Primero, agrega un ID al vínculo de apertura de la navegación lateral:
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
A continuación, agrega un ID al vínculo de cierre de la navegación lateral:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
Esto concluye el diseño de apilamiento adaptable de la macro <body>
y nos vincula a la barra de URL.
Continuemos.
El diseño de <aside>
también es ordenado. Tiene 2 elementos secundarios: un <nav>
, que es el componente con aspecto de papel que se desliza hacia afuera, y un elemento de vínculo de cierre <a>
que establece que la URL debe ser #
.
El vínculo es invisible a la derecha de la navegación desplegable de papel, de modo que las personas puedan "hacer clic fuera" del componente visual para descartarlo.
Agrega el siguiente código CSS a css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Me pareció que la proporción y los nombres eran un detalle muy agradable, en el que la cuadrícula podía destacarse y brindarle al diseñador mucho control.
A continuación, debo superponer de forma condicional el contenido principal y mantener mi posición durante el desplazamiento del documento. Este es un excelente trabajo para position: sticky
y algunos overscroll-behavior
.
Agrega los siguientes estilos para la navegación lateral:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
Esos estilos garantizan que la navegación lateral tenga la altura de la ventana gráfica, se desplace verticalmente y contenga el desplazamiento. Lo que es muy importante es que oculta el elemento. De forma predeterminada, cuando el viewport es 540px
o más pequeño, se oculta esa navegación lateral. A menos que…
Agrega un seudoselector :target
al elemento #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
Cuando el ID de ese elemento y la barra de URL sean iguales, establece visibility
en visible
. Abre el menú lateral después de desplazarte por la página o intenta desplazarte por la página mientras el menú lateral está abierto. ¿Qué opinas?
Agrega el siguiente código CSS a la parte inferior de app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
Estos diseños tienen como objetivo nuestros botones de abrir y cerrar, especifican sus diseños de presión y táctiles, y también los ocultan cuando los puertos de visualización son 540px
o más grandes.
Para darle un toque especial, agreguemos transformaciones de CSS con accesibilidad respetuosa.
Agrega el siguiente código CSS a css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
Agrega un poco de JavaScript
La tecla Escape
debería cerrar el menú. Agrega este código JS a js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
Esto escucha un evento de tecla en el elemento de navegación lateral.
Si es Escape
, establece el hash de la URL como vacío, lo que hace que la navegación lateral desaparezca.
La siguiente parte del código JS de UX es la administración del enfoque. Quiero que abrir y cerrar sea fácil, por lo que espero hasta que la navegación lateral haya terminado algún tipo de transición y, luego, la verifico con el hash de la URL para determinar si está dentro o fuera. Luego, uso JavaScript para establecer el enfoque en el botón complementario al que acaba de presionar.
Agrega el siguiente código JavaScript a js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
Probar
- Para obtener una vista previa del sitio, presiona Ver app y, luego, Pantalla completa
.
Conclusión
Eso es todo lo que necesitaba del componente. No dudes en desarrollarla, controlarla con el estado de JavaScript en lugar de la URL y, en general, hacerla tuya. Siempre hay más para agregar o más casos de uso para cubrir.
Abre css/brandnav.css
para consultar los estilos no relacionados con el diseño que apliqué a este componente. No creía que fuera importante para el conjunto de funciones en el que me estaba enfocando, y esperaba que separar los diseños de la disposición fomentara el uso de copiar y pegar. ¡Puede que haya más aprendizaje para ti allí!
¿Cómo se crean componentes de navegación lateral responsivos que se deslizan hacia afuera? ¿Alguna vez tuviste más de 1, como uno de cada lado? Me encantaría mostrar tu solución en un video de YouTube. Asegúrate de enviarme un tuit o publicar un comentario en YouTube con tu código. ¡Ayudará a todos!