Beispiel:CSS Menu9.html
<!DOCTYPE html> <html lang="de"> <head>
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css">
<title>Menü 9</title> <script> document.addEventListener('DOMContentLoaded', function () {
dropdownExtension();
function dropdownExtension () {
const submenus = document.querySelectorAll('nav li > ul');
for(let submenu of submenus) {
submenu.classList.add('submenu');
submenu.insertAdjacentHTML('beforebegin', `
<button aria-expanded="false">
Untermenü aufklappen
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'>
<path d='M0.3,0.1 0.3,0.9 0.8,0.5z' />
</svg>
</button>
`);
}
document.documentElement.addEventListener('click', event => {
if (event.target.tagName == 'BUTTON' && event.target.hasAttribute('aria-expanded')) {
event.target.setAttribute('aria-expanded', event.target.getAttribute('aria-expanded') != 'true');
event.target.nextElementSibling.classList.toggle('visible');
event.target.parentNode.childNodes.classList.toggle('visible');
}
});
document.addEventListener('mouseover', (event) => {
if (!event.target.classList.contains('visible')) {
hideSubmenu();
}
});
document.addEventListener('keyup', (event) => { if (event.key === 'Escape') { hideSubmenu(); }
if ((event.key === 'Tab') && (!event.target.closest('.visible')) ) {
hideSubmenu();
} });
function hideSubmenu() { let buttons = document.querySelectorAll('[aria-expanded="true"]'); buttons.forEach(function(button) { button.setAttribute('aria-expanded', 'false'); }); let elements = document.querySelectorAll('.visible'); elements.forEach(function(element) { element.classList.remove('visible'); }); } }
const cssRules = ` nav > ul { list-style:none;
// Safari hack, see https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html list-style: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'/%3E");
margin: 0; padding: 0; display: flex; flex-direction: column;
} nav ul {
position:relative;
}
nav li {
margin: 0.25em; padding: 0; font-size: 1.5rem; flex: 1 1 0%; position: relative;
}
@media (min-width: 45em) {
nav > ul { flex-direction: row;
height: 3em;
} nav li { flex: 1;
flex-basis: 12em;
flex-grow: 0; flex-shrink: 0;
font-size: 1em;
}
}
nav a {
display: block; padding: 0.4em; text-decoration: none; font-weight: bold; text-align: center; border: thin solid var(--background-color); border-radius: .5em; color: var(--link-color); --link-color: gold; background-color: var(--background-color); transition: all .25s ease-in; position: relative;
}
nav li[aria-current] a {
background-color: var(--accent2-color); color: var(--accent1-color);
}
nav a:focus,
nav a:hover,
nav li[aria-current] a:focus,
nav li[aria-current] a:hover {
color: var(--background-color); background-color: var(--accent1-color);
}
/* submenu navigation links */ nav ul ul {
visibility: hidden; height: 0; z-index: 1000;
}
nav ul ul ul{
position: absolute; left: 7em; /* top: 0em; */
} nav ul ul ul li {
width: 10em;
}
nav ul li {
display: block;
}
/* Show the submenu on hover, but not when nav li button:hover */
nav li:hover > ul { visibility: visible; height: auto;
}
nav li button:hover ~ ul { visibility: hidden; height: 0;
}
nav li button:hover ~ ul.visible,
.visible {
visibility: visible; height: auto;
}
[aria-expanded] { position: absolute; right: 0.5em; top: 0.25em; width:2em; height:2em; padding: 0; color: var(--accent1-color); background: var(--background-color); /* damit er bei nav a:focus noch sichtbar ist */ outline:transparent; border: thin solid var(--background-color); border-radius: 0.3em;
}
[aria-expanded] svg { pointer-events: none;
fill: var(--accent1-color);
border-radius: 0.3em; z-index:10; }
nav li:hover [aria-expanded] svg { background: var(--accent1-color); fill: var(--background-color); }
nav li:focus [aria-expanded] svg { background: var(--background-color);
fill: var(--accent1-color);
}
[aria-expanded]:focus svg, [aria-expanded]:hover svg{
fill: var(--background-color);
background: var(--accent1-color);
}
[aria-expanded="true"] svg {
transform: translate(0,0) rotate(90deg);
}
.visually-hidden, [visually-hidden="true"] { position: absolute !important; clip-path: rect(1px, 1px, 1px, 1px) !important; padding: 0 !important; border: 0 !important; height: 1px !important; width: 1px !important; overflow: hidden !important; }
- root {
--background-color: midnightblue; --accent1-color: gold; --accent2-color: darkred; --text-color: black; }`;
const stylesheet = document.createElement('style'); stylesheet.textContent = cssRules; stylesheet.id = 'CSS-for-dropdown-navigation'; document.querySelector('html > head').appendChild(stylesheet);
});
</script>
<style>
kbd {
background: #f9f9f9 linear-gradient(to bottom, #eee, #f9f9f9, #eee) repeat scroll 0 0; border: thin solid #aaa; border-radius: 2px; box-shadow: 1px 2px 2px #ddd; font-family: inherit; font-size: 0.9em; padding: 0 0.5em;
} </style>
</head>
<body>
Menü 9: Kopiervorlage
<nav>
- <a href="#">Seite 1</a>
- <a href="#">Seite 2</a>
- <a href="#2a">Seite 2a</a>
- <a href="#2aI">Seite 2aI</a>
- <a href="#2aII">Seite 2aII</a>
- <a href="#2b">Seite 2b</a>
- <a href="#2a">Seite 2a</a>
- <a href="#">aktuelle Seite</a>
- <a href="#">Seite 4</a>
- <a href="#4a">Seite 4a</a>
- <a href="#4b">Seite 4b</a>
- <a href="#4c">Seite 4c</a>
- <a href="#">Seite 5</a>
</nav>
Dieses Beispiel erweitert die CSS-basierte Variante um einige Zusatzfunktionen, die das Dropdown-Menü für alle benutzbar machen.
Ziele sind:
- HTML: verschachtelte Listen mit bis zu drei Ebenen ohne Klassen
- CSS: Auf schmalen Viewports vertikal - auf genügend breiten Viewports horizontal angeordnet.
- JavaScript Bedienung mit Maus, Touch und Tastatur
- Jedes Listenelement mit einer Unterliste enthält zwei UI-Elemente:
- den eigentlichen Link auf eine Unterseite und …
- einen dynamisch erzeugten Button zum Öffnen/Schließen des Untermenüs.
- Links und Buttons können mit der Tab-Taste ↹ angetabbt und dann mit⏎ oder Space ausgewählt werden.
(Shift+↹ führt zurück!) - ESC schließt das aufgeklappte Menü
- Jedes Listenelement mit einer Unterliste enthält zwei UI-Elemente:
Kopiere das JavaScript in eine eigene Datei und binde sie in jeder Seite deiner Webpräsenz ein.
</body> </html>