74 lines
2.8 KiB
JavaScript
74 lines
2.8 KiB
JavaScript
(() => {
|
|
const navigation = document.querySelector('.site-navigation');
|
|
if (!navigation) return;
|
|
|
|
const button = navigation.querySelector('.menu-toggle');
|
|
const links = navigation.querySelector('#navigation-links');
|
|
const backdrop = navigation.querySelector('.site-navigation__backdrop');
|
|
if (!button || !links || !backdrop) return;
|
|
|
|
// Muss zum Grenzwert in navigation.css passen.
|
|
const mobileView = window.matchMedia('(max-width: 1100px)');
|
|
|
|
function setMenuOpen(isOpen) {
|
|
isOpen = isOpen && mobileView.matches;
|
|
navigation.classList.toggle('is-open', isOpen);
|
|
button.setAttribute('aria-expanded', String(isOpen));
|
|
button.setAttribute('aria-label', isOpen ? 'Menü schließen' : 'Menü öffnen');
|
|
button.textContent = isOpen ? '✕' : '☰';
|
|
}
|
|
|
|
button.addEventListener('click', () => {
|
|
setMenuOpen(button.getAttribute('aria-expanded') !== 'true');
|
|
});
|
|
|
|
// Nach einem Sprung bleibt der Tastaturfokus im gewählten Bereich.
|
|
links.addEventListener('click', (event) => {
|
|
const link = event.target.closest('a');
|
|
if (!link || !mobileView.matches) return;
|
|
setMenuOpen(false);
|
|
const target = document.querySelector(link.getAttribute('href'));
|
|
if (target) {
|
|
const hadTabindex = target.hasAttribute('tabindex');
|
|
if (!hadTabindex) target.setAttribute('tabindex', '-1');
|
|
requestAnimationFrame(() => target.focus({ preventScroll: true }));
|
|
if (!hadTabindex) {
|
|
target.addEventListener('blur', () => target.removeAttribute('tabindex'), { once: true });
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Escape' && button.getAttribute('aria-expanded') === 'true') {
|
|
setMenuOpen(false);
|
|
button.focus();
|
|
}
|
|
});
|
|
|
|
backdrop.addEventListener('click', () => {
|
|
setMenuOpen(false);
|
|
button.focus();
|
|
});
|
|
|
|
// Das Menü bleibt beim Weitergehen mit Tab nicht über dem Seiteninhalt liegen.
|
|
navigation.addEventListener('focusout', (event) => {
|
|
if (!navigation.contains(event.relatedTarget)) setMenuOpen(false);
|
|
});
|
|
|
|
mobileView.addEventListener('change', () => {
|
|
const focusedElement = document.activeElement;
|
|
setMenuOpen(false);
|
|
if (mobileView.matches && links.contains(focusedElement)) button.focus();
|
|
if (!mobileView.matches && focusedElement === button) links.querySelector('a')?.focus();
|
|
});
|
|
|
|
// Berücksichtigt auch umgebrochene Texte und vergrößerte Schrift.
|
|
const headerObserver = new ResizeObserver(() => {
|
|
document.documentElement.style.setProperty(
|
|
'--navigation-offset', `${navigation.getBoundingClientRect().height}px`
|
|
);
|
|
});
|
|
headerObserver.observe(navigation);
|
|
setMenuOpen(false);
|
|
})();
|