From 96a698ebdc33925c52f7d24dedd1816363b82ca9 Mon Sep 17 00:00:00 2001 From: fs Date: Mon, 27 Jul 2026 09:46:40 +0200 Subject: [PATCH] =?UTF-8?q?Mobiles=20Men=C3=BC=20als=20Drawer:=20oben=20ve?= =?UTF-8?q?rankert,=20Accordion=20statt=20Sprung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Das Overlay war vertikal zentriert. Beim Aufklappen eines Dropdowns wuchs die Liste und rezentrierte sich — der gerade angetippte Punkt sprang unter dem Finger weg, bei langen Menüs lief der Inhalt aus dem Screen (nicht scrollbar). Jetzt ist die Liste oben verankert (justify-content: flex-start, padding unter Header + Logo-Überhang) und scrollbar mit overscroll-behavior: contain. Punkte sind volle Tap-Breite mit Hairline-Trennern, Chevron rechtsbündig, aktive Seite mit rotem Balken links. Untermenüs animieren über die 0fr/1fr-Zeile des li-Grids statt display: none — weiches Auf-/Zuklappen ohne Layout-Sprung. Unterpunkte in Abel statt Coolvetica (unter 28px unleserlich, siehe CLAUDE.md), linksbündig, Desktop-Panel-Optik im Overlay komplett zurückgesetzt (inkl. backdrop-filter/radius/translateX, die sonst durchschlugen). nav.js setzt .site-nav--js auf die Nav: nur ohne JS öffnet :focus-within die Untermenüs. Mit JS wäre das ein Bug — der Button behält nach dem Tipp den Fokus, das Menü ließe sich nie wieder zuklappen. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU --- public/assets/css/layout.css | 135 +++++++++++++++++++++++++++++------ public/assets/js/nav.js | 5 ++ 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/public/assets/css/layout.css b/public/assets/css/layout.css index 5bed31d..27038fc 100644 --- a/public/assets/css/layout.css +++ b/public/assets/css/layout.css @@ -264,6 +264,12 @@ z-index: 30; } + /* Logo/Brand ebenfalls über dem Overlay halten — Orientierung bei offenem Menü. */ + .site-header__brand { + position: relative; + z-index: 30; + } + .site-nav { order: 3; margin-left: 0; @@ -317,59 +323,146 @@ transform: translateY(-9px) rotate(-45deg); } + /* Overlay: oben verankert + scrollbar — beim Aufklappen eines Dropdowns bleibt + der angetippte Punkt stehen (kein Re-Zentrier-Sprung), lange Menüs laufen + nicht mehr aus dem Screen. */ .site-nav__list { position: fixed; inset: 0; z-index: 20; flex-direction: column; - justify-content: center; - gap: 1.75rem; - background: rgb(0 0 0 / 0.91); - font-size: var(--fs-700); + justify-content: flex-start; + align-items: stretch; + gap: 0; + overflow-y: auto; + overscroll-behavior: contain; + background: rgb(8 8 8 / 0.96); + font-size: var(--fs-650); + text-align: left; visibility: hidden; opacity: 0; transition: opacity var(--transition), visibility var(--transition); } + /* Padding separat mit (0,2,0): der reset-Selektor ul[class] (0,1,1) würde + es auf der Ein-Klassen-Regel überschreiben. Links auf --container-pad, + damit die Menüpunkte mit dem Logo fluchten. */ + .site-nav .site-nav__list { + /* Oben: Header + Logo-Überhang (Logo ragt unter den Header) + Luft. */ + padding: calc(var(--header-h) + 4rem) var(--container-pad) 3rem; + } + + @supports (backdrop-filter: blur(1px)) { + .site-nav__list { + background: rgb(8 8 8 / 0.85); + backdrop-filter: blur(18px) saturate(1.3); + } + } + .site-nav__list a:not(.btn) { font-family: var(--ff-heading); text-transform: uppercase; } - /* Dropdown im Overlay: Trigger wie die anderen Punkte, Untermenü inline darunter. */ - .site-nav__sublink { - font-family: var(--ff-heading); - font-size: var(--fs-700); - text-transform: uppercase; - justify-content: center; + /* Drawer-Zeilen: volle Tap-Breite mit Hairline-Trennern statt frei schwebender + Punkte — Chevron sitzt rechtsbündig, aktive Seite bekommt den roten Balken + links (die Desktop-Unterstreichung wird hier neutralisiert). Untermenü-Höhe + animiert über die 0fr/1fr-Zeile des li-Grids (weicher Accordion-Effekt). */ + .site-nav__list > .site-nav__item { + border-bottom: 1px solid var(--clr-glass-border); } - /* Im Overlay inline einklappen — display statt visibility, sonst bliebe Platz reserviert. - Spezifität (0,2,0) gleich der Desktop-Regel; gewinnt hier per Quell-Reihenfolge. */ + .site-nav__list > .site-nav__item > a:not(.btn), + .site-nav__sublink { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 1rem 0.25rem; + border-bottom: 0; + font-family: var(--ff-heading); + font-size: var(--fs-650); + text-transform: uppercase; + } + + .site-nav__list > .site-nav__item > a[aria-current="page"], + .site-nav__sublink[data-current] { + border-bottom: 0; + box-shadow: inset 3px 0 0 var(--clr-accent); + padding-left: 1rem; + } + + /* Volle Breite + zentrierter Text: Items und Untermenüs zentrieren sich am + Screen (nicht am shrink-gewrappten li), Unterstreichungen bleiben textbreit. */ + .site-nav__item--has-submenu { + display: grid; + grid-template-rows: auto 0fr; + transition: grid-template-rows var(--transition); + } + + .site-nav__item--has-submenu:has(> .site-nav__sublink[aria-expanded="true"]) { + grid-template-rows: auto 1fr; + } + + /* Ohne JS gibt es kein aria-expanded-Toggling — dann (und nur dann) öffnet + :focus-within. Mit JS wäre :focus-within ein Bug: der Button behält nach + dem Tipp den Fokus, das Menü ließe sich nie wieder zuklappen. */ + .site-nav:not(.site-nav--js) .site-nav__item--has-submenu:focus-within { + grid-template-rows: auto 1fr; + } + + /* Desktop-Panel-Optik komplett zurücksetzen (inkl. backdrop-filter/radius — + sonst schimmert das Glas-Panel im Overlay durch). Spezifität (0,2,0) gleich + der Desktop-Regel; gewinnt hier per Quell-Reihenfolge. */ .site-nav__list .site-nav__submenu { position: static; transform: none; - display: none; - opacity: 1; - visibility: visible; + display: grid; + min-height: 0; + overflow: hidden; + opacity: 0; + visibility: hidden; gap: 0.25rem; min-width: 0; - margin: 0.75rem 0 0; + justify-self: stretch; + margin: 0; + /* Kein Padding am ul: bei border-box könnte die 0fr-Zeile sonst nicht auf 0 + kollabieren (ungleiche Abstände). Luft macht das letzte Kind-li. Keine + Einrückung — Hierarchie kommt aus Schriftart/-größe und Farbe. */ padding: 0; background: none; + backdrop-filter: none; border: 0; + border-radius: 0; box-shadow: none; - text-align: center; + text-align: left; + transition: opacity var(--transition), visibility var(--transition); } - .site-nav__item--has-submenu:focus-within > .site-nav__submenu, - .site-nav__sublink[aria-expanded="true"] + .site-nav__submenu { - display: grid; + .site-nav__sublink[aria-expanded="true"] + .site-nav__submenu, + .site-nav:not(.site-nav--js) .site-nav__item--has-submenu:focus-within > .site-nav__submenu { + opacity: 1; + visibility: visible; + /* Desktop-Open-Regel (0,3,0) setzt translateX(-50%) — hier neutralisieren, + sonst hängt das Untermenü halb aus dem Screen. */ + transform: none; } + .site-nav__list .site-nav__submenu > li:last-child { + padding-bottom: 0.75rem; + } + + /* Unterpunkte in Abel, Groß-/Kleinschreibung — wie im Desktop-Dropdown + (Coolvetica-Condensed-Uppercase wird unter 28px unleserlich). Bündig mit + den Hauptpunkten; die aktive Unterseite rückt per Desktop-Regel mit + Akzentbalken + Tint leicht ein. */ .site-nav__list .site-nav__submenu a:not(.btn) { - font-size: var(--fs-600); + padding: 0.6rem 0.25rem; + font-family: var(--ff-body); + font-size: var(--fs-500); + text-transform: none; color: var(--clr-text-muted); + white-space: normal; } body.nav-open .site-nav__list { diff --git a/public/assets/js/nav.js b/public/assets/js/nav.js index 7acaa19..679192b 100644 --- a/public/assets/js/nav.js +++ b/public/assets/js/nav.js @@ -11,6 +11,11 @@ return; } + // Marker fürs CSS: mit JS steuert allein aria-expanded die Dropdowns, + // der :focus-within-Fallback (No-JS) wird abgeschaltet (sonst ließe sich + // ein Untermenü auf Touch nie wieder zuklappen). + toggle.closest('.site-nav').classList.add('site-nav--js'); + var subToggles = Array.prototype.slice.call(list.querySelectorAll('.site-nav__sublink')); function closeSubmenus(except) {