Refactor navigation hamburger menu to an accordion
This commit is contained in:
parent
64b49b5048
commit
00baf37c40
|
@ -1,21 +1,34 @@
|
||||||
|
{# Accessible hamburger menu code based on:
|
||||||
|
https://kalechips.net/projects/snippets/burger #}
|
||||||
|
|
||||||
|
{% set navLinksEl %}{% block navbarLinks %}{{ navbarLinks }}{% endblock %}{% endset %}
|
||||||
|
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<button class="navbar__toggle" aria-label="Navigation menu toggle" aria-expanded="false">
|
<details class="navbar__burger">
|
||||||
<span aria-hidden="true">☰</span>
|
<summary class="navbar__toggle" id="toggle">☰ Navigation</summary>
|
||||||
<h2 class="navbar__title">Navigation</h2>
|
<nav class="navbar__menu">
|
||||||
</button>
|
<ul class="navbar__menu--links">
|
||||||
|
{{ navLinksEl | safe }}
|
||||||
|
<li class="skip"><a href="#toggle">Close Menu</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</details>
|
||||||
<ul class="navbar__links">
|
<ul class="navbar__links">
|
||||||
{% block navbarLinks %}
|
{{ navLinksEl | safe }}
|
||||||
{{ navbarLinks }}
|
|
||||||
{% endblock %}
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--icon-burger: url(/assets/icons/burger.svg);
|
||||||
|
--icon-close: url(/assets/icons/close.svg);
|
||||||
|
--sz-icon: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
background: var(--clr-navbar-bg);
|
background: var(--clr-navbar-bg);
|
||||||
padding: 0.6em 1em;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 999;
|
z-index: 998;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
@ -24,35 +37,39 @@
|
||||||
.navbar__title {
|
.navbar__title {
|
||||||
color: var(--clr-navbar-link);
|
color: var(--clr-navbar-link);
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar__toggle {
|
.navbar__toggle {
|
||||||
|
list-style-type: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.3em;
|
gap: 0.3em;
|
||||||
border: none;
|
padding: 0.6em;
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar__toggle::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar__toggle:focus,
|
.navbar__toggle:focus,
|
||||||
.navbar__links a:focus {
|
.navbar a:focus {
|
||||||
outline: 0.15em solid var(--clr-navbar-link);
|
outline: 0.15em solid var(--clr-navbar-link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar a:focus {
|
||||||
|
outline-offset: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar__menu--links,
|
||||||
.navbar__links {
|
.navbar__links {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0.2em 0 0 0;
|
|
||||||
display: none;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar__links--show {
|
.navbar__menu--links a,
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar__links a {
|
.navbar__links a {
|
||||||
color: var(--clr-navbar-link);
|
color: var(--clr-navbar-link);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -60,6 +77,31 @@
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar__menu--links {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip a {
|
||||||
|
position: absolute;
|
||||||
|
left: -10000px;
|
||||||
|
top: auto;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip a:focus {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar__links {
|
||||||
|
display: none;
|
||||||
|
padding: 0.2em 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar__links a:hover {
|
.navbar__links a:hover {
|
||||||
color: var(--clr-link-hover);
|
color: var(--clr-link-hover);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +116,10 @@
|
||||||
padding: 0 0.6em;
|
padding: 0 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar__burger {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar__toggle {
|
.navbar__toggle {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -88,44 +134,15 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script defer>
|
<script defer>
|
||||||
{# Accessible hamburger menu navigation script based on:
|
window.onload = () => {
|
||||||
https://accessibleweb.dev/navigation #}
|
const navbarBurger = document.querySelector(".navbar__burger");
|
||||||
const navbarToggle = document.querySelector(".navbar__toggle");
|
|
||||||
const navbarLinksClass = ".navbar__links";
|
|
||||||
const navbarLinks = document.querySelector(navbarLinksClass);
|
|
||||||
const showNavLinksClass = "navbar__links--show";
|
|
||||||
const navbarLinkItems = document.querySelectorAll(navbarLinksClass + " li a");
|
|
||||||
|
|
||||||
const openNavigation = () => {
|
navbarBurger.addEventListener("keydown", (event) => {
|
||||||
navbarLinks.classList.add(showNavLinksClass);
|
const key = event.code;
|
||||||
navbarToggle.ariaExpanded = "true";
|
if (key == "Escape") {
|
||||||
};
|
navbarBurger.removeAttribute("open");
|
||||||
|
document.querySelector(".navbar__toggle").focus();
|
||||||
const closeNavigation = () => {
|
|
||||||
navbarLinks.classList.remove(showNavLinksClass);
|
|
||||||
navbarToggle.ariaExpanded = "false";
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleNavigation = () => {
|
|
||||||
const open = navbarToggle.ariaExpanded;
|
|
||||||
open === "false" ? openNavigation() : closeNavigation();
|
|
||||||
}
|
|
||||||
|
|
||||||
navbarToggle.addEventListener("click", toggleNavigation);
|
|
||||||
|
|
||||||
window.addEventListener("keyup", (e) => {
|
|
||||||
if (e.key === "Escape") {
|
|
||||||
navbarToggle.focus();
|
|
||||||
closeNavigation();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleBlur = (event) => {
|
|
||||||
const navList = event.currentTarget.closest(navbarLinksClass);
|
|
||||||
if (!event.relatedTarget || !navList.contains(event.relatedTarget)) {
|
|
||||||
closeNavigation();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
navbarLinkItems[navbarLinkItems.length - 1].addEventListener("blur", handleBlur);
|
|
||||||
</script>
|
</script>
|
Loading…
Reference in New Issue