Cómo crear un menú fuera del lienzo (off-canvas) con CSS y un toque de JavaScript
Spanish (Español) translation by Carlos (you can also view the original English article)
En este tutorial veremos un método simple, pero efectivo, para crear un menú fuera del lienzo (off-canvas) con HTML, CSS y JavaScript.
Para tener una idea inicial de lo que vamos a crear, mira la demostración en CodePen (revisa la versión más grande para una mejor experiencia):
Nota: Este tutorial no se enfocará en cómo hacer que el menú fuera del lienzo sea accesible o responsivo, por lo que esos serían, sin duda, los siguientes pasos válidos.
1. Inicia con el marcado
Nuestro marcado consiste en dos elementos de envoltura:
- el elemento
.top-banner - el elemento
.top-nav
Aquí está el código HTML:
1 |
<section class="top-banner"> |
2 |
<div class="top-banner-overlay"> |
3 |
<!-- content here -->
|
4 |
</div>
|
5 |
</section>
|
6 |
|
7 |
<nav class="top-nav"> |
8 |
<div class="menu-wrapper"> |
9 |
<!-- content here -->
|
10 |
</div>
|
11 |
<div class="fixed-menu"> |
12 |
<!-- content here -->
|
13 |
</div>
|
14 |
</nav>
|
2. A continuación necesitamos algo de CSS
Con el marcado preparado, a continuación examinemos los estilos más importantes que se requieren para nuestro menú.
Nota: En aras de la legibilidad, este código CSS no está optimizado, notarás propiedades duplicadas que quizá quieras eliminar en tu propia versión.
Estilizando el elemento top-banner
El elemento .top-banner se ve así:



En torno a sus estilos, hacemos lo siguiente:
- Ajusta su ancho igual al ancho de la ventana menos el ancho del elemento
.menu-wrapper.
- Ajusta su altura igual a la altura de la ventana.
- Defínelo como un contenedor flexible. Esto forzará a su superposición para que cubra toda la altura del elemento principal.
- Usa flexbox para centrar de manera vertical el contenido de la superposición.
Aquí están los estilos que necesitaremos para lograr todo eso:
1 |
.top-banner { |
2 |
display: flex; |
3 |
width: calc(100% - 150px); |
4 |
height: 100vh; |
5 |
transform: translateX(150px); |
6 |
background: url(IMAGE_PATH) no-repeat center / fixed; |
7 |
}
|
8 |
|
9 |
.top-banner-overlay { |
10 |
display: flex; |
11 |
flex-direction: column; |
12 |
justify-content: center; |
13 |
width: 350px; |
14 |
padding: 20px; |
15 |
transition: transform .7s; |
16 |
color: white; |
17 |
background: rgba(0, 0, 0, .7); |
18 |
}
|
Estilizando al elemento top-nav
El elemento .top-nav se ve así:



En este caso, haremos lo siguiente:
- Especificamos los elementos secundarios directos como elementos fijos que cubren la altura de la ventana.
- Utilizamos flexbox para alinear verticalmente el elemento
.fixed-menu. - De manera predeterminada, ocultamos el elemento
.menu-wrapper.Para hacerlo, no le damos un valor de propiedad comodisplay: none. De hecho, usamos la funcióntranslate ()para moverlo 200 px hacia la izquierda. Recuerda que el ancho del elemento es de 350 px, por lo que parte de él todavía está dentro de la ventana gráfica. No obstante, no es visible porque el elemento está posicionado debajo del elemento.fixed-menu. - Ocultamos la lista del menú.
Mira los estilos CSS correspondientes a continuación:
1 |
.top-nav .menu-wrapper { |
2 |
position: fixed; |
3 |
top: 0; |
4 |
left: 0; |
5 |
bottom: 0; |
6 |
width: 350px; |
7 |
padding: 20px; |
8 |
transform: translateX(-200px); |
9 |
transition: transform .7s; |
10 |
background: #B1FFE5; |
11 |
}
|
12 |
|
13 |
.top-nav .menu-wrapper .menu { |
14 |
opacity: 0; |
15 |
transition: opacity .4s; |
16 |
}
|
17 |
|
18 |
.top-nav .fixed-menu { |
19 |
position: fixed; |
20 |
top: 0; |
21 |
left: 0; |
22 |
bottom: 0; |
23 |
display: flex; |
24 |
flex-direction: column; |
25 |
width: 150px; |
26 |
padding: 20px; |
27 |
background: aquamarine; |
28 |
}
|
3. Ahora algo de JavaScript
En este punto, utilizaremos un sencillo código de JavaScript para manipular el estado del menú fuera del lienzo.
Describamos las acciones necesarias:
- Cuando se hace clic en el botón
.menu-open, el menú debe aparecer con un agradable efecto deslizante hacia dentro y, simultáneamente, la superposición debe ser empujada hacia la derecha. De forma opcional, podemos hacer muchas más cosas durante este estado. En nuestro ejemplo, añadimos una sombra al seudoelemento::beforede la superposición y revelamos la lista del menú usando un efecto de desvanecimiento. - Cuando se hace clic en el botón
.menu-close, el menú debería desaparecer con un agradable efecto deslizante hacia fuera y, simultáneamente, la superposición debe ser empujada hacia la izquierda.
Aquí está el código JavaScript que implementa este comportamiento:
1 |
const menuOpen = document.querySelector(".top-nav .menu-open"); |
2 |
const menuClose = document.querySelector(".top-nav .menu-close"); |
3 |
const menuWrapper = document.querySelector(".top-nav .menu-wrapper"); |
4 |
const topBannerOverlay = document.querySelector(".top-banner-overlay"); |
5 |
|
6 |
function toggleMenu() { |
7 |
menuOpen.addEventListener("click", () => { |
8 |
menuWrapper.classList.add("is-opened"); |
9 |
topBannerOverlay.classList.add("is-moved"); |
10 |
});
|
11 |
|
12 |
menuClose.addEventListener("click", () => { |
13 |
menuWrapper.classList.remove("is-opened"); |
14 |
topBannerOverlay.classList.remove("is-moved"); |
15 |
});
|
16 |
}
|
17 |
|
18 |
toggleMenu(); |
Y en seguida encontrarás los estilos CSS asociados:
1 |
.top-banner-overlay.is-moved { |
2 |
transform: translateX(350px); |
3 |
}
|
4 |
|
5 |
.top-banner-overlay.is-moved::before { |
6 |
content: ''; |
7 |
position: absolute; |
8 |
top: 0; |
9 |
bottom: 0; |
10 |
right: 100%; |
11 |
width: 20px; |
12 |
box-shadow: 0 0 10px black; |
13 |
}
|
14 |
|
15 |
.top-nav .menu-wrapper.is-opened { |
16 |
transform: translateX(150px); |
17 |
}
|
18 |
|
19 |
.top-nav .menu-wrapper.is-opened .menu { |
20 |
opacity: 1; |
21 |
transition-delay: .6s; |
22 |
}
|
4. Compatibilidad con navegadores
Esta demostración funcionará bien únicamente en los navegadores de escritorio. Los dispositivos móviles requerirán un diseño de página diferente, pero eso está fuera del alcance de este tutorial. Como siempre, utilizamos Babel para compilar el código ES6 a ES5.
El único pequeño problema que encontré mientras lo probaba es el cambio en la representación del texto que ocurre cuando se anima la superposición. Aunque probé varios enfoques propuestos en diferentes hilos de Stack Overflow, no pude hallar una solución simple para todos los sistemas operativos y navegadores. Así que ten presente que quizá veas problemas de representación (rendering) de las fuentes pequeñas mientras se anima la superposición.
Conclusión
¡Eso es todo, amigos! Logramos crear un útil menú fuera del lienzo con un código relativamente sencillo.
Espero que hayas disfrutado el resultado final y que lo uses como inspiración para crear menús fuera del lienzo aún más potentes. Y por supuesto, si creas alguno, ¡no olvides compartirlo con nosotros!
Aprende más técnicas fuera del lienzo


CSSCómo crear una navegación off-canvas (fuera del lienzo) con CSS GridIan Yates

Diseño de navegaciónCómo crear una navegación fuera del lienzo con jQuery.mmenuGeorge Martsoukos

Diseño web responsivoCómo crear un diseño de navegación fuera del lienzo con BootstrapThoriq Firdaus

Diseño web responsivoConsejo rápido: no olvides la metaetiqueta ViewportIan Yates



