{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "gleitender-indikator",
 "name": "Gleitender Indikator / Segment-Schalter mit Pille",
 "name_en": "Sliding nav indicator / magic line / Segmented control / toggle group with sliding pill",
 "kurz": "Pille, Unterstrich und Segment-Schalter gleiten per CSS Anchor Positioning zum Ziel, 250 ms mit der bei COLLINS gemessenen Kurve.",
 "kategorie": "Navigation",
 "kategorie_slug": "navigation",
 "kategorie_nr": 3,
 "bau_chat": "C3",
 "prioritaet": "A",
 "trendstatus": "etabliert",
 "belegstatus": "belegt",
 "website_belege": 3,
 "stimmung": [
  "ruhig",
  "präzise"
 ],
 "stimmung_roh": [
  "präzise",
  "ruhig",
  "technisch",
  "modern"
 ],
 "technik": [
  "css",
  "anchor-positioning",
  "motion",
  "vanilla-js"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Ein einziges Element markiert den aktiven oder gehoverten Punkt: ein Unterstrich, ein Punkt oder eine Hintergrund-Pille. Beim Wechsel gleitet es von der alten zur neuen Position und passt seine Breite an, statt zu springen. Typische Formen sind die Hover-Pille in der Navigation, der wandernde Tab-Unterstrich und der Segment-Schalter, dessen Pille zur gewählten Option gleitet. 2026 geht das ohne JavaScript per CSS Anchor Positioning: Das Ziel bekommt anchor-name, das Pseudo-Element des Containers richtet sich per anchor() daran aus und transitioniert seine inset-Werte.",
  "warum_es_wirkt": "Kontinuität: Das Auge folgt einem Objekt, so wird der Zustandswechsel verständlich. Ein kleines Detail mit großem Qualitätsgefühl. Besonders stark wirkt es zusammen mit animierten Preisen in einem Preis-Umschalter.",
  "wann_einsetzen": "Tabs, Pill-Navigationen, Filterleisten, Segment-Schalter, Sprach- und Theme-Schalter, Ansichtsumschalter (Raster oder Liste), Preis-Umschalter (monatlich oder jährlich), Einstellungen.",
  "wann_nicht": "Bei Mehrseiten-Navigation mit vollem Neuladen fehlt die alte Position. Dann nur mit Cross-Document View Transition oder gar nicht. Bei mehr als 4 bis 5 Optionen, dann besser Dropdown oder scrollbare Tabs. Wenn die Optionen sehr unterschiedlich lang sind und umbrechen.",
  "varianten": [
   "Hover-Pille: folgt dem Zeiger über die Links und kehrt beim Verlassen zum aktiven Punkt zurück (COLLINS)",
   "Tab-Unterstrich, der beim Wechsel wandert (Chrome-Anleitung, Cursor)",
   "Segment-Schalter: Pille ankert am Label der gewählten Radio-Option",
   "Gleiten oder Dehnen: beide Kanten gleichzeitig oder die führende Kante zuerst",
   "Punkt oder Balken in vertikalen Leisten (Stripe: Höhe per anchor-size)",
   "Glas-Indikator mit Glassmorphism",
   "Preis-Umschalter mit animierten Zahlen (Motion AnimateNumber)",
   "Framework-Varianten: Motion layoutId (Shared Layout), Radix NavigationMenu.Indicator mit CSS-Variablen, Base UI oder Radix Toggle Group mit Motion"
  ],
  "umsetzung": "Tab-Unterstrich: .tabs { position: relative } .tabs [aria-selected=true] { anchor-name: --tab } .tabs::after { content: ''; position: absolute; position-anchor: --tab; left: anchor(left); right: anchor(right); top: calc(anchor(bottom) - 2px); height: 2px } @media (prefers-reduced-motion: no-preference) { .tabs::after { transition: left .25s cubic-bezier(.215,.61,.355,1), right .25s cubic-bezier(.215,.61,.355,1) } }. Nicht position-area verwenden, das ist nicht transitionierbar.\n\nHover-Pille: a:hover, a:focus-visible { anchor-name: --pille }; den aktiven Punkt mit .nav:has(a:hover) a[aria-current] { anchor-name: none } freigeben. Pille 0,5rem breiter als der Eintrag: left: calc(anchor(left) - .25rem). Hover-Regeln in @media (hover: hover) legen.\n\nSegment-Schalter: <fieldset> mit <legend> und Radios, label:has(:checked) { anchor-name: --seg }, Pille als ::before der Spur mit z-index: -1 und isolation: isolate. Die Radios behalten die native Pfeiltasten-Steuerung.\n\nDehnen: JS setzt data-richtung, die folgende Kante bekommt ein transition-delay. Die Richtung aus der DOM-Reihenfolge bestimmen und vorher kein Layout lesen, sonst startet die Transition noch mit der alten Richtung.\n\nFallback: @supports not (position-anchor: --a) misst JS die Position (getBoundingClientRect oder offsetLeft/offsetWidth) und schreibt CSS-Variablen, dieselben Transitions greifen. Ohne JS: statischer border-bottom bzw. Hintergrund am gewählten Label.",
  "mobil": "Funktioniert bei Tap identisch. Die Hover-Pille entfällt, die Pille sitzt am aktiven Punkt und gleitet beim Antippen.",
  "reduzierte_bewegung": "Transition entfernen, der Indikator springt. Die Chrome-Anleitung sieht das bereits so vor.",
  "barrierefreiheit": "Der Indikator ist dekorativ. Den Zustand zwingend über aria-current=page bzw. aria-selected abbilden und nicht nur über Farbe oder Pille zeigen, etwa mit einem zusätzlichen Punkt. Segment-Schalter als Radiogruppe mit fieldset und legend (oder role=radiogroup). Tabs mit role=tablist, tab und tabpanel und Pfeiltasten-Steuerung."
 },
 "messwerte": {
  "easing": "cubic-bezier(.215,.61,.355,1) (Collins)",
  "dauer_ms": "250 (Position), 500 (Opacity)",
  "stagger_ms": "",
  "distanz": "Pille 0.5rem breiter als der Eintrag",
  "sonstiges": "CSS Anchor Positioning auf drei Produktionsseiten; Schatten 0 12px 31px #0000001f (Collins)",
  "herkunft": "beobachtet",
  "quelle": "https://www.wearecollins.com/",
  "aus_eintrag": [
   "gleitender-indikator"
  ]
 },
 "kurve": {
  "bezier": [
   0.215,
   0.61,
   0.355,
   1.0
  ],
  "css": "cubic-bezier(0.215, 0.61, 0.355, 1)",
  "name": "eigene Kurve",
  "dauer_ms": 250
 },
 "gesehen_bei": [
  {
   "seite": "Chrome Developers: Anchor Positioning Tab Underline",
   "url": "https://developer.chrome.com/docs/modern-web-guidance/guides/ui-behaviors/anchor-positioning-tab-underline?hl=en",
   "auszeichnung": "",
   "beobachtung": "Offizielle Anleitung: Unterstrich als ::before, anchor-name am aktiven li, inset-Transition .2s, Fallback border-bottom.",
   "art": "artikel",
   "weitere_beobachtung": "Indikator per anchor() und Transition auf inset (0.2 s), position-area nicht transitionierbar."
  },
  {
   "seite": "FreeFrontend: CSS Anchor Positioning Navigation Effect (01/2026)",
   "url": "https://freefrontend.com/code/css-anchor-positioning-navigation-effect-2026-01-22/",
   "auszeichnung": "",
   "beobachtung": "Im Suchergebnis als 2026er Demo gelistet (Seiteninhalt beim Abruf nicht passend).",
   "art": "artikel"
  },
  {
   "seite": "FreeFrontend: Resizing Tab Bar with Anchor Positioning (03/2026)",
   "url": "https://freefrontend.com/code/resizing-tab-bar-with-anchor-positioning-2026-03-28/",
   "auszeichnung": "",
   "beobachtung": "Nur Titel gesehen.",
   "art": "artikel"
  },
  {
   "seite": "Radix Primitives: Navigation Menu",
   "url": "https://radix-ui.com/primitives/docs/components/navigation-menu",
   "auszeichnung": "",
   "beobachtung": "Indicator-Teil mit data-state visible/hidden und Translate-Variablen.",
   "art": "artikel"
  },
  {
   "seite": "Motion Examples: Price switcher",
   "url": "https://motion.dev/examples/vue-number-price-switcher",
   "auszeichnung": "",
   "beobachtung": "Preise wechseln animiert mit AnimateNumber.",
   "art": "demo"
  },
  {
   "seite": "Motion Examples: Base UI Toggle group",
   "url": "https://motion.dev/examples/react-base-toggle-group",
   "auszeichnung": "",
   "beobachtung": "Animierte Toggle-Gruppe.",
   "art": "demo"
  },
  {
   "seite": "COLLINS",
   "url": "https://www.wearecollins.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (Inline-CSS): @supports (position-anchor:--thumb) – eine Pille (ul:before) folgt per anchor() dem gehoverten Listeneintrag (.program:has(a:hover){anchor-name:--thumb}), transition .25s all var(--ease-out-cubic), .5s opacity; Fallback pro Eintrag.",
   "art": "website"
  },
  {
   "seite": "Stripe",
   "url": "https://stripe.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (d0587afad5d01631.css): .hds-side-nav__list:after mit inset-block-start:anchor(top), height:anchor-size(height), position-anchor:--active-nav; aktiver Link [aria-current] setzt anchor-name:--active-nav.",
   "art": "website"
  },
  {
   "seite": "Cursor",
   "url": "https://cursor.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft (3g8c5788oj-t7.css): Tabs mit data-[state=active]:[anchor-name:--active-tab] und Indikator [position-anchor:--active-tab].",
   "art": "website"
  }
 ],
 "tutorials": [
  {
   "titel": "Chrome Developers: Anchor positioning tab underline",
   "url": "https://developer.chrome.com/docs/modern-web-guidance/guides/ui-behaviors/anchor-positioning-tab-underline?hl=en"
  },
  {
   "titel": "Motion: Tab select (layoutId)",
   "url": "https://motion.dev/tutorials/react-tab-select"
  },
  {
   "titel": "Codrops: Inspiration for Navigation Indicators (2016, Grundlagen)",
   "url": "https://tympanus.net/codrops/2016/09/02/inspiration-navigation-indicators/"
  }
 ],
 "kombinierbar_mit": [
  "schwebende-pill-navigation",
  "mega-menue-morphing-viewport",
  "theme-umschalter-view-transition",
  "scrollspy-kapitelnavigation",
  "zahlen-odometer",
  "token-federnd-verspielt",
  "toggle-switch"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/navigation/gleitender-indikator/",
  "meta": "https://cecodesign.de/lab/fundus/navigation/gleitender-indikator/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/navigation/gleitender-indikator/demo"
 },
 "herkunft": {
  "quelldateien": [
   "navigation.json",
   "hover.json",
   "patch-belege-3.json"
  ],
  "pruefnotizen": [
   "patch-belege-3.json: Drei Produktionsbelege mit Anchor Positioning."
  ],
  "zusammengelegt_aus": [
   "gleitender-indikator",
   "segment-schalter"
  ],
  "querverweis_kategorien": [
   "Mikroanimationen"
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Pille, Unterstrich und Segment-Schalter gleiten per CSS Anchor Positioning zum Ziel, 250 ms mit der bei COLLINS gemessenen Kurve.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.215, 0.61, 0.355, 1) (easeOutCubic, gemessen bei COLLINS)",
   "dauer_ms": 250,
   "dauer_ms_hinweis": "Position (left, right, top, bottom) und Textfarbe",
   "deckkraft_ms": 500,
   "dehnen_versatz_ms": 120,
   "dehnen_hinweis": "Variante Dehnen (eigener Wert): führende Kante sofort, folgende Kante mit 120 ms transition-delay",
   "pille_ueberstand": "0.25rem je Seite (Pille 0.5rem breiter als der Eintrag)",
   "pille_schatten": "0 12px 31px #0000001f",
   "pille_radius": "999px",
   "unterstrich": "2px hoch, Radius 2px, sitzt auf 1px-Grundlinie",
   "segment": "Spur 1px Rand, 3px Innenabstand, Pille in Tintenfarbe, Labeltext wechselt mit 250 ms auf Papierfarbe",
   "inhalte_einblenden": "opacity 0 → 1, translateY 10px → 0, 500 ms, Versatz 40 ms je Element, gleiche Kurve",
   "technik": "anchor-name am Ziel (aria-current, aria-selected, label:has(:checked), :hover), position-anchor am ::before/::after des Containers, Transition auf left/right/top/bottom",
   "fallback": "@supports not (position-anchor: --a): JS misst per getBoundingClientRect und schreibt --l/--r/--t/--b",
   "farben": "Grund #fafafa, Pille #ffffff, Tinte #121316 (Segment-Pille), Markenton #4b45d9 (Tab-Unterstrich, Punkt am aktuellen Eintrag)",
   "vorfuehrung_runde_ms": 11400
  },
  "ausloeser": "klick",
  "touch": "Hover-Pille entfällt (Hover-Regeln nur unter hover: hover). Antippen setzt aria-current bzw. wählt Tab und Ansicht, alle drei Indikatoren gleiten wie am Desktop. Tabs füllen die Breite, Segment-Schalter darunter, Funktionskarten zweispaltig.",
  "reduziert": "Alle Transitions der Indikatoren und Textfarben aus: Pille, Unterstrich und Segment-Pille springen. Gefilterte Funktionen erscheinen ohne Einblenden. Die Werte-Leiste zeigt den Zustand an.",
  "korrekturen": {
   "beschreibung": "Ein einziges Element markiert den aktiven oder gehoverten Punkt: ein Unterstrich, ein Punkt oder eine Hintergrund-Pille. Beim Wechsel gleitet es von der alten zur neuen Position und passt seine Breite an, statt zu springen. Typische Formen sind die Hover-Pille in der Navigation, der wandernde Tab-Unterstrich und der Segment-Schalter, dessen Pille zur gewählten Option gleitet. 2026 geht das ohne JavaScript per CSS Anchor Positioning: Das Ziel bekommt anchor-name, das Pseudo-Element des Containers richtet sich per anchor() daran aus und transitioniert seine inset-Werte.",
   "warum_es_wirkt": "Kontinuität: Das Auge folgt einem Objekt, so wird der Zustandswechsel verständlich. Ein kleines Detail mit großem Qualitätsgefühl. Besonders stark wirkt es zusammen mit animierten Preisen in einem Preis-Umschalter.",
   "wann_einsetzen": "Tabs, Pill-Navigationen, Filterleisten, Segment-Schalter, Sprach- und Theme-Schalter, Ansichtsumschalter (Raster oder Liste), Preis-Umschalter (monatlich oder jährlich), Einstellungen.",
   "wann_nicht": "Bei Mehrseiten-Navigation mit vollem Neuladen fehlt die alte Position. Dann nur mit Cross-Document View Transition oder gar nicht. Bei mehr als 4 bis 5 Optionen, dann besser Dropdown oder scrollbare Tabs. Wenn die Optionen sehr unterschiedlich lang sind und umbrechen.",
   "varianten": [
    "Hover-Pille: folgt dem Zeiger über die Links und kehrt beim Verlassen zum aktiven Punkt zurück (COLLINS)",
    "Tab-Unterstrich, der beim Wechsel wandert (Chrome-Anleitung, Cursor)",
    "Segment-Schalter: Pille ankert am Label der gewählten Radio-Option",
    "Gleiten oder Dehnen: beide Kanten gleichzeitig oder die führende Kante zuerst",
    "Punkt oder Balken in vertikalen Leisten (Stripe: Höhe per anchor-size)",
    "Glas-Indikator mit Glassmorphism",
    "Preis-Umschalter mit animierten Zahlen (Motion AnimateNumber)",
    "Framework-Varianten: Motion layoutId (Shared Layout), Radix NavigationMenu.Indicator mit CSS-Variablen, Base UI oder Radix Toggle Group mit Motion"
   ],
   "umsetzung": "Tab-Unterstrich: .tabs { position: relative } .tabs [aria-selected=true] { anchor-name: --tab } .tabs::after { content: ''; position: absolute; position-anchor: --tab; left: anchor(left); right: anchor(right); top: calc(anchor(bottom) - 2px); height: 2px } @media (prefers-reduced-motion: no-preference) { .tabs::after { transition: left .25s cubic-bezier(.215,.61,.355,1), right .25s cubic-bezier(.215,.61,.355,1) } }. Nicht position-area verwenden, das ist nicht transitionierbar.\n\nHover-Pille: a:hover, a:focus-visible { anchor-name: --pille }; den aktiven Punkt mit .nav:has(a:hover) a[aria-current] { anchor-name: none } freigeben. Pille 0,5rem breiter als der Eintrag: left: calc(anchor(left) - .25rem). Hover-Regeln in @media (hover: hover) legen.\n\nSegment-Schalter: <fieldset> mit <legend> und Radios, label:has(:checked) { anchor-name: --seg }, Pille als ::before der Spur mit z-index: -1 und isolation: isolate. Die Radios behalten die native Pfeiltasten-Steuerung.\n\nDehnen: JS setzt data-richtung, die folgende Kante bekommt ein transition-delay. Die Richtung aus der DOM-Reihenfolge bestimmen und vorher kein Layout lesen, sonst startet die Transition noch mit der alten Richtung.\n\nFallback: @supports not (position-anchor: --a) misst JS die Position (getBoundingClientRect oder offsetLeft/offsetWidth) und schreibt CSS-Variablen, dieselben Transitions greifen. Ohne JS: statischer border-bottom bzw. Hintergrund am gewählten Label.",
   "mobil": "Funktioniert bei Tap identisch. Die Hover-Pille entfällt, die Pille sitzt am aktiven Punkt und gleitet beim Antippen.",
   "reduzierte_bewegung": "Transition entfernen, der Indikator springt. Die Chrome-Anleitung sieht das bereits so vor.",
   "barrierefreiheit": "Der Indikator ist dekorativ. Den Zustand zwingend über aria-current=page bzw. aria-selected abbilden und nicht nur über Farbe oder Pille zeigen, etwa mit einem zusätzlichen Punkt. Segment-Schalter als Radiogruppe mit fieldset und legend (oder role=radiogroup). Tabs mit role=tablist, tab und tabpanel und Pfeiltasten-Steuerung."
  },
  "geprueft": "01.11.2026",
  "notiz": "Funktionsseite der erfundenen Dienstplanungs-Software Kadenz, gestaltet nach dem Rezept saas-produkt-praezise (Geist und Geist Mono, Graustufen auf #fafafa, ein Markenton #4b45d9). Hover-Pille in der Hauptnavigation (Funktionen, Preise, Changelog, Kunden), Tab-Unterstrich filtert acht Funktionen nach Planen, Team, Zeit & Lohn, Segment-Schalter Karten/Liste. Die Karten zeigen eigene SVG-Ausschnitte der Produktoberfläche (Wochenplan, Besetzung, Ruhezeit-Prüfung, Schichttausch, Verfügbarkeiten, Push, Stempeluhr, Lohnexport), keine fremden Bilder. Alles per CSS Anchor Positioning; JS nur für Zustände, Richtung (Variante Dehnen) und den Mess-Fallback. Bewegungswerte unverändert (250 ms, COLLINS-Kurve). Umschalter Gleiten/Dehnen, Werte-Leiste unten. Vorführung: Zeiger fährt die Navigation ab, klickt Filter und Ansicht, jede zweite Runde im Modus Dehnen. Der Seitenwechsel in der Navigation ist als Zustand simuliert; bei echter Mehrseiten-Navigation braucht die Pille eine Cross-Document View Transition. 01.11.2026 (AD): Markenname gegen einen erfundenen getauscht, um Verwechslung mit einer echten Marke zu vermeiden. Zugang 02.11.2026: Zweite Titelzeile #a3a6ad → #898d95 (3,2:1 für großen Text). Bis 360 px Navigationspille enger (7px 8px, 13 px) und Tabs dürfen umbrechen, damit bei 320 px nichts quer scrollt. Kontrastmodus: Knöpfe und Tabs mit Rahmen ButtonText. Tabs mit wanderndem Tabindex und Pfeiltasten sind absichtlich nicht einzeln fokussierbar."
 }
}
