{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "native-popover-dropdowns",
 "name": "Native Dropdowns mit Popover-API, Anchor Positioning und Invokern",
 "name_en": "Native popover menus (popover + anchor positioning + invoker commands)",
 "kurz": "Kursmenü, Coaching-Menü und Sprachwahl als native Popover: Der Invoker öffnet, Anchor Positioning platziert und klappt am Rand um, @starting-style blendet ein.",
 "kategorie": "Navigation",
 "kategorie_slug": "navigation",
 "kategorie_nr": 3,
 "bau_chat": "C3",
 "prioritaet": "B",
 "trendstatus": "aufsteigend",
 "belegstatus": "belegt",
 "website_belege": 4,
 "stimmung": [
  "ruhig",
  "präzise"
 ],
 "stimmung_roh": [
  "technisch",
  "ruhig",
  "robust"
 ],
 "technik": [
  "css",
  "popover",
  "anchor-positioning",
  "invoker-commands"
 ],
 "technik_gruppen": [
  "css"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Untermenüs und Hovercards sind HTML-Popover: popover=auto für Menüs, popover=hint für Hinweise und Hovercards. Ein Button öffnet sie ohne JavaScript per command/commandfor oder popovertarget. Klick daneben und Escape schließen (Light-Dismiss), das liefert der Browser. Die Lage am Auslöser regelt CSS Anchor Positioning mit position-area. Am Rand klappt das Popover per position-try-fallbacks um. Ein- und Ausblenden laufen über @starting-style und transition-behavior: allow-discrete auf display und overlay. Öffnen beim Hover geht künftig deklarativ mit interestfor.",
  "warum_es_wirkt": "Weniger JavaScript, robuste Fokus- und Schließlogik, Darstellung im Top-Layer ohne z-index-Kämpfe. Man spürt diese technische Qualität als Ruhe und Zuverlässigkeit.",
  "wann_einsetzen": "Dropdowns, Sprachauswahl, Account-Menüs und Hovercards in der Navigation. Auch als Grundlage für Mega-Menüs.",
  "wann_nicht": "Wenn ältere Browser ohne Fallback bedient werden müssen. Bei Mega-Menüs mit morphendem Viewport, dort bleibt eine Messung per JavaScript nötig.",
  "varianten": [
   "popover=auto mit popovertarget (Baseline)",
   "Invoker: command=\"toggle-popover\" mit commandfor",
   "Hover-Intent per Skript: showPopover() beim Hover, hidePopover() nach 200 ms (Warp)",
   "popover=hint mit interestfor für Hovercards (experimentell)",
   "Implizite Anker-Verknüpfung zwischen Popover und Auslöser (Chrome 133)"
  ],
  "umsetzung": "HTML: <button commandfor=\"m1\" command=\"toggle-popover\">Kurse</button> <div id=\"m1\" popover><ul>…Links…</ul></div>. CSS: button { anchor-name: --m1 } #m1 { margin: 0; inset: auto; position-anchor: --m1; position-area: bottom span-right; position-try-fallbacks: flip-inline; margin-top: 10px; opacity: 0; translate: 0 -6px; transition: opacity .15s, translate .15s, display .15s allow-discrete, overlay .15s allow-discrete } #m1:popover-open { opacity: 1; translate: 0; transition-duration: .2s } @starting-style { #m1:popover-open { opacity: 0; translate: 0 -6px } }. Kurve cubic-bezier(0.22, 1, 0.36, 1). Fallbacks: @supports (position-area: bottom) für die Lage, Abfrage von HTMLElement.prototype.showPopover für Popover und von 'commandForElement' in HTMLButtonElement.prototype für Invoker (sonst popovertarget setzen). Fallstrick: Popover sind kein Menü im Sinne von ARIA. Links in einer <ul> lassen, kein role=menu für Seitennavigation.",
  "mobil": "Tippen öffnet, Tippen daneben schließt. Auf schmalen Bildschirmen das Popover über die volle Breite legen und nur die Oberkante am Anker ausrichten (top: calc(anchor(bottom) + 8px)). Wie interestfor auf Touch reagiert, ist laut Chrome noch offen. Hinweise deshalb zusätzlich per Tippen öffnen. Light-Dismiss: Seit Chrome 154 schließen Popover (popover=auto) und Dialog erst beim click, nicht mehr bei pointerdown. Wer auf dem Telefon in der Seite wischt oder mit rechts klickt, schließt ein offenes Menü dort nicht mehr; in älteren Versionen konnte das passieren. Eigene Schließ-Logik (etwa der Fallback ohne Popover-API) deshalb ebenfalls auf click legen (Chrome-154-Versionshinweise).",
  "reduzierte_bewegung": "Weg und Skalierung entfernen. Höchstens kurz überblenden.",
  "barrierefreiheit": "Der Browser setzt aria-expanded am Invoker selbst und gibt den Fokus beim Schließen zurück. Der Popover-Inhalt folgt in der Tab-Reihenfolge direkt auf den Auslöser. Für Navigationsmenüs Disclosure-Semantik statt role=menu. Hinweise mit role=tooltip und aria-describedby an den Auslöser binden."
 },
 "messwerte": {
  "easing": "",
  "dauer_ms": "Schließverzögerung 200 (Warp)",
  "stagger_ms": "",
  "distanz": "",
  "sonstiges": "Hover-Intent per Timeout statt interestfor",
  "herkunft": "beobachtet",
  "quelle": "https://www.warp.dev/_next/static/immutable/chunks/04tk4lrdulyrx.js"
 },
 "kurve": {
  "bezier": [
   0.22,
   1.0,
   0.36,
   1.0
  ],
  "css": "cubic-bezier(0.22, 1, 0.36, 1)",
  "name": "power4.out",
  "dauer_ms": 200
 },
 "gesehen_bei": [
  {
   "seite": "Chrome Developers: New in Web UI (I/O 2025 Recap)",
   "url": "https://developer.chrome.com/blog/new-in-web-ui-io-2025-recap",
   "auszeichnung": "",
   "beobachtung": "Popover Baseline (Chrome 114, Firefox 125, Safari 17); Invoker command/commandfor (Chrome 135, Firefox 144, Safari 26.2); Anchor Positioning (Chrome 125, Firefox 147, Safari 26); interestfor laut Artikel Chrome 151 / Firefox 153 (Versionsangaben laut Artikel, unsicher).",
   "art": "artikel"
  },
  {
   "seite": "Chrome Developers: Popover = hint",
   "url": "https://developer.chrome.com/blog/popover-hint",
   "auszeichnung": "",
   "beobachtung": "popover=hint ab Chrome 133; Hint-Popover schließen Menüs nicht; Beispiel mit position-area.",
   "art": "artikel"
  },
  {
   "seite": "Vercel",
   "url": "https://vercel.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft: HTML <div id=\"logo-branding-menu\" popover=\"manual\" role=\"menu\">; Chunk 245rvpx4746i9.js ruft showPopover({source}) bzw. hidePopover().",
   "art": "website",
   "browser_gemessen": true
  },
  {
   "seite": "Warp",
   "url": "https://www.warp.dev/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (Chunk 04tk4lrdulyrx.js): Nav-Flyouts öffnen per showPopover() beim Hover, Schließen über setTimeout → hidePopover() nach 200 ms.",
   "art": "website"
  },
  {
   "seite": "Webflow",
   "url": "https://webflow.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (marketing-main.webflow.shared…css): Plattform-Komponente .w-popover[popover]:not(:popover-open){display:none}, .w-popover{position-anchor:none}; dieselbe Regel steckt in allen geprüften Webflow-Seiten (OFF+BRAND, Lando Norris, Osmo).",
   "art": "website"
  },
  {
   "seite": "Stripe",
   "url": "https://stripe.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (d0587afad5d01631.css): .hds-popover mit @supports (anchor-name:--test-anchor){.hds-positioner--anchored{position:fixed; top:calc(anchor(bottom) + …)}}.",
   "art": "website"
  }
 ],
 "tutorials": [
  {
   "titel": "Chrome Developers: Popover = hint",
   "url": "https://developer.chrome.com/blog/popover-hint"
  },
  {
   "titel": "Chrome Developers: New in Web UI (I/O 2025)",
   "url": "https://developer.chrome.com/blog/new-in-web-ui-io-2025-recap"
  }
 ],
 "kombinierbar_mit": [
  "mega-menue-morphing-viewport",
  "kompakte-expandierende-navigation",
  "theme-umschalter-view-transition"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/navigation/native-popover-dropdowns/",
  "meta": "https://cecodesign.de/lab/fundus/navigation/native-popover-dropdowns/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/navigation/native-popover-dropdowns/demo"
 },
 "herkunft": {
  "quelldateien": [
   "navigation.json",
   "patch-belege-3.json"
  ],
  "pruefnotizen": [
   "patch-belege-3.json: Vier Produktionsbelege; Webflow liefert Popover inzwischen als Standardkomponente."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Kursmenü, Coaching-Menü und Sprachwahl als native Popover: Der Invoker öffnet, Anchor Positioning platziert und klappt am Rand um, @starting-style blendet ein.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.22, 1, 0.36, 1)",
   "dauer_ms": "Öffnen 200, Schließen 150",
   "stagger_ms": "25 je Eintrag, Startverzögerung 40",
   "distanz": "Menü translate 0 -6px + scale .98 → 0 / 1; Einträge translate 0 4px; Hinweis translate 0 4px",
   "popover": "popover=auto für Menüs, popover=hint für den Ratenhinweis, Zeiger der Vorführung popover=manual",
   "invoker": "command=\"toggle-popover\" + commandfor; ohne Invoker-Unterstützung popovertarget",
   "anker": "anchor-name je Auslöser, position-anchor am Popover; position-area: bottom span-right; position-try-fallbacks: flip-inline; margin-top 10px",
   "hinweis": "interestfor; position-area: top; position-try-fallbacks: flip-block; margin-bottom 10px; Breite 250px",
   "hover_intent": "Variante Hover: showPopover({ source }) bei pointerenter, hidePopover() 200 ms nach pointerleave (Warp); Klick fixiert",
   "telefon": "unter 640px: position-area none, top calc(anchor(bottom) + 8px), left/right 16px",
   "chevron": "rotate 180deg, 200 ms, gleiche Kurve",
   "panel": "Radius 16px, Innenabstand 8px, Kursmenü max. 620px, Coaching 380px, Sprache 220px",
   "reduziert": "nur opacity 100 ms linear, kein Weg, kein Scale, keine Staffel"
  },
  "ausloeser": "klick",
  "touch": "Tippen öffnet über den Invoker, Tippen daneben schließt (Light-Dismiss). Unter 640px nutzen die Menüs die volle Breite mit 16px Rand, nur die Oberkante hängt am Anker. In der Hover-Variante öffnet Tippen wie ein Klick. Der Ratenhinweis öffnet per Tippen.",
  "reduziert": "Menüs und Hinweis blenden nur 100 ms linear über, ohne Weg, Skalierung und Staffel; Chevron dreht ohne Übergang.",
  "korrekturen": {
   "beschreibung": "Untermenüs und Hovercards sind HTML-Popover: popover=auto für Menüs, popover=hint für Hinweise und Hovercards. Ein Button öffnet sie ohne JavaScript per command/commandfor oder popovertarget. Klick daneben und Escape schließen (Light-Dismiss), das liefert der Browser. Die Lage am Auslöser regelt CSS Anchor Positioning mit position-area. Am Rand klappt das Popover per position-try-fallbacks um. Ein- und Ausblenden laufen über @starting-style und transition-behavior: allow-discrete auf display und overlay. Öffnen beim Hover geht künftig deklarativ mit interestfor.",
   "warum_es_wirkt": "Weniger JavaScript, robuste Fokus- und Schließlogik, Darstellung im Top-Layer ohne z-index-Kämpfe. Man spürt diese technische Qualität als Ruhe und Zuverlässigkeit.",
   "wann_einsetzen": "Dropdowns, Sprachauswahl, Account-Menüs und Hovercards in der Navigation. Auch als Grundlage für Mega-Menüs.",
   "wann_nicht": "Wenn ältere Browser ohne Fallback bedient werden müssen. Bei Mega-Menüs mit morphendem Viewport, dort bleibt eine Messung per JavaScript nötig.",
   "varianten": [
    "popover=auto mit popovertarget (Baseline)",
    "Invoker: command=\"toggle-popover\" mit commandfor",
    "Hover-Intent per Skript: showPopover() beim Hover, hidePopover() nach 200 ms (Warp)",
    "popover=hint mit interestfor für Hovercards (experimentell)",
    "Implizite Anker-Verknüpfung zwischen Popover und Auslöser (Chrome 133)"
   ],
   "umsetzung": "HTML: <button commandfor=\"m1\" command=\"toggle-popover\">Kurse</button> <div id=\"m1\" popover><ul>…Links…</ul></div>. CSS: button { anchor-name: --m1 } #m1 { margin: 0; inset: auto; position-anchor: --m1; position-area: bottom span-right; position-try-fallbacks: flip-inline; margin-top: 10px; opacity: 0; translate: 0 -6px; transition: opacity .15s, translate .15s, display .15s allow-discrete, overlay .15s allow-discrete } #m1:popover-open { opacity: 1; translate: 0; transition-duration: .2s } @starting-style { #m1:popover-open { opacity: 0; translate: 0 -6px } }. Kurve cubic-bezier(0.22, 1, 0.36, 1). Fallbacks: @supports (position-area: bottom) für die Lage, Abfrage von HTMLElement.prototype.showPopover für Popover und von 'commandForElement' in HTMLButtonElement.prototype für Invoker (sonst popovertarget setzen). Fallstrick: Popover sind kein Menü im Sinne von ARIA. Links in einer <ul> lassen, kein role=menu für Seitennavigation.",
   "mobil": "Tippen öffnet, Tippen daneben schließt. Auf schmalen Bildschirmen das Popover über die volle Breite legen und nur die Oberkante am Anker ausrichten (top: calc(anchor(bottom) + 8px)). Wie interestfor auf Touch reagiert, ist laut Chrome noch offen. Hinweise deshalb zusätzlich per Tippen öffnen. Light-Dismiss: Seit Chrome 154 schließen Popover (popover=auto) und Dialog erst beim click, nicht mehr bei pointerdown. Wer auf dem Telefon in der Seite wischt oder mit rechts klickt, schließt ein offenes Menü dort nicht mehr; in älteren Versionen konnte das passieren. Eigene Schließ-Logik (etwa der Fallback ohne Popover-API) deshalb ebenfalls auf click legen (Chrome-154-Versionshinweise).",
   "reduzierte_bewegung": "Weg und Skalierung entfernen. Höchstens kurz überblenden.",
   "barrierefreiheit": "Der Browser setzt aria-expanded am Invoker selbst und gibt den Fokus beim Schließen zurück. Der Popover-Inhalt folgt in der Tab-Reihenfolge direkt auf den Auslöser. Für Navigationsmenüs Disclosure-Semantik statt role=menu. Hinweise mit role=tooltip und aria-describedby an den Auslöser binden."
  },
  "geprueft": "01.11.2026",
  "notiz": "Welt: Rezept kurs-coaching-lernweg (führt native-popover-dropdowns selbst unter Navigation) mit der erfundenen Kernberg Schreibschule aus Jena; Bricolage Grotesque, Onest, Shantell Sans nur für Etiketten und Randnotiz, Königsblau als Markenton, Grün nur im Lernweg. Gezeigt: Kursmenü (zweispaltig), Coaching-Menü und Sprachwahl als popover=auto mit command/commandfor, Lage per Anchor Positioning; die Sprachwahl sitzt am rechten Rand und klappt per flip-inline nach links. Der Ratenhinweis ist popover=hint mit interestfor und schließt offene Menüs nicht. Umschalter Klick/Hover: Hover nutzt den bei Warp gemessenen Intent (200 ms Schließverzögerung) per Skript, interestfor nur für den Hinweis. Die Vorführung klickt die echten Invoker (button.click()), Light-Dismiss und Escape werden per hidePopover() nachgestellt; der Zeiger liegt als popover=manual im Top-Layer. Auch die Randnotiz im Manuskript hängt per Anchor Positioning an der markierten Stelle. Geprüft in Chromium 153 (Invoker, Anchor, hint, interestfor vorhanden); Fallbacks für fehlende Invoker (popovertarget) und fehlendes Anchor Positioning (Messen per getBoundingClientRect). AD-Review 01.11.2026: Note 5. Korrektur 02.11.2026: mobil um Light-Dismiss ab Chrome 154 ergänzt (click statt pointerdown, Scrollen schließt nicht mehr; Chrome-Versionshinweise per Abruf geprüft)."
 }
}
