{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "text-hervorhebung-highlight",
 "name": "Text-Hervorhebung mit ::highlight()",
 "name_en": "Text highlighting with the CSS Custom Highlight API",
 "kurz": "Suchtreffer, eigene Markierungen und verlinkte Textstellen leuchten im Text einer Apotheke auf, ohne ein einziges <mark> im HTML: Range-Objekte plus ::highlight(), Rückfall <mark>.",
 "kategorie": "Typo-Techniken",
 "kategorie_slug": "typo-techniken",
 "kategorie_nr": 15,
 "bau_chat": "C1",
 "prioritaet": "F",
 "trendstatus": "aufsteigend",
 "belegstatus": "quellenbelegt",
 "website_belege": 0,
 "stimmung": [
  "ruhig",
  "editorial",
  "präzise"
 ],
 "stimmung_roh": [
  "präzise",
  "ruhig",
  "editorial"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "css-highlight-api",
  "aria-live"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Suchtreffer, eigene Markierungen beim Lesen oder eine verlinkte Textstelle werden farbig hervorgehoben, ohne dass ein einziges <mark> oder <span> ins HTML kommt. JavaScript beschreibt die Stellen als Range-Objekte, CSS gestaltet sie mit ::highlight(name). Mehrere Arten (Treffer, aktueller Treffer, eigene Notiz) liegen als eigene Highlights übereinander. Browser ohne die API bekommen <mark> als Rückfall.",
  "warum_es_wirkt": "Treffer zu markieren macht eine Suche nachvollziehbar: Man sieht, warum ein Eintrag passt. Weil der DOM nicht umgebaut wird, bleiben Links, Auswahl, Screenreader-Text und Event-Handler heil, und auch große Texte bleiben schnell. Es ist der Text-Marker des Webs, nicht nur Gestaltung.",
  "wann_einsetzen": "FAQ- und Hilfeseiten mit Suche, Speisekarten (Allergene, vegan), Download-Center, Leistungslisten, Ratgeber mit „Stelle merken“, geteilte Links auf eine bestimmte Passage. Apotheke, Praxis, Gastronomie, Kurse.",
  "wann_nicht": "Nicht für dauerhafte, inhaltliche Betonung im Text (dafür <strong>, <em> oder highlight-marker-underline). Nicht, wenn der Treffer selbst interaktiv werden soll (Klick auf den Treffer): Highlights sind keine Elemente. Kein Ersatz für eine Suche, die Ergebnisse filtert, sie ergänzt sie.",
  "varianten": [
   "Suche: Treffer live markieren, aktueller Treffer eigener Stil, mit Vor und Zurück",
   "Lesen: Text auswählen, „Markieren“, Markierungen bleiben (localStorage) und sind als Liste anspringbar",
   "Verlinkte Stelle: Link öffnet die Seite mit hervorgehobener Passage, die in Stufen abklingt"
  ],
  "umsetzung": "1. Text bleibt unverändert im HTML. 2. Suchen: Mit einem TreeWalker (NodeFilter.SHOW_TEXT) alle Textknoten im Suchbereich durchgehen, Fundstellen per indexOf auf der kleingeschriebenen, entakzentuierten Fassung finden (normalize('NFD') ohne Kombinationszeichen, so findet „schussler“ auch „Schüßler“ nur, wenn man ß gesondert behandelt) und je Treffer new Range() mit setStart/setEnd anlegen. 3. CSS.highlights.set('treffer', new Highlight(...ranges)) und für den aktuellen Treffer ein zweites Highlight mit höherer priority. 4. Stil: ::highlight(treffer) { background-color; color } und ::highlight(treffer-aktiv) mit kräftigerer Farbe plus text-decoration als Zusatz (Safari ignoriert Dicke und Abstand). 5. Zum aktuellen Treffer springen: range.getBoundingClientRect() und scrollBy; Ansage „Treffer 3 von 7“ in einer aria-live-Zeile. 6. Lesen: window.getSelection().getRangeAt(0) im erlaubten Bereich in ein eigenes Highlight übernehmen, als Textversatz (Absatz-Index, Start, Ende) in localStorage sichern und beim Laden zurückbauen. 7. Verlinkte Stelle: ?stelle=absatz:start-ende in der URL; beim Laden Range bauen, hinscrollen und das Highlight in vier Stufen über eigene Namen (stelle-1 … stelle-4, abnehmende Deckkraft) abklingen lassen, weil ::highlight keine Transition kann. 8. Rückfall ohne CSS.highlights: Treffer mit <mark> umschließen und vor jeder neuen Suche wieder auspacken (normalize()).",
  "mobil": "Suchfeld oben klebend, Vor und Zurück als große Knöpfe daneben. Markieren beim Lesen über die native Textauswahl; der Knopf „Markieren“ erscheint unten fest statt über der Auswahl, damit er nicht mit dem System-Menü kollidiert.",
  "reduzierte_bewegung": "Sprung zum Treffer ohne Gleiten. Die verlinkte Stelle bleibt markiert statt abzuklingen, bis man sie schließt.",
  "barrierefreiheit": "Highlights sind für Screenreader unsichtbar. Deshalb Trefferzahl und Position per aria-live ansagen („Treffer 2 von 5“). Farbe nie allein: der aktive Treffer bekommt zusätzlich eine Unterstreichung. Kontrast der Markierung zum Text mindestens 4,5:1. Im Kontrastmodus (forced-colors) ::highlight mit Highlight und HighlightText. Eigene Markierungen haben eine Liste mit Text und Knopf „Entfernen“."
 },
 "messwerte": {
  "easing": "keine Transition möglich; Abklingen in Stufen",
  "dauer_ms": "Suche 120 entprellt; verlinkte Stelle hält 1600, dann 4 Stufen à 300",
  "stagger_ms": "",
  "distanz": "Sprung zum Treffer mit 30 % Abstand von oben",
  "sonstiges": "Mehrere Highlights mit priority: aktiver Treffer 2, Treffer 1, eigene Markierung 0",
  "herkunft": "eigene Festlegung",
  "quelle": "Rezept apotheke-vor-ort"
 },
 "kurve": null,
 "gesehen_bei": [
  {
   "seite": "web.dev: Interop 2026",
   "url": "https://web.dev/blog/interop-2026",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026 (Beitrag 12.02.2026): Custom Highlights sind ein Schwerpunkt von Interop 2026: „Custom highlights let you style arbitrary text ranges without adding extra elements to the DOM.“",
   "art": "artikel"
  },
  {
   "seite": "web.dev: New to the web platform in June 2025",
   "url": "https://web.dev/blog/web-platform-06-2025",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: Firefox 140 implementiert die CSS Custom Highlight API; wegen Fehlern bei ::highlight damals noch nicht ganz Baseline.",
   "art": "artikel"
  },
  {
   "seite": "MDN: ::highlight()",
   "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/::highlight",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: Baseline 2026 (neu verfügbar seit März 2026). Erlaubt sind color, background-color, text-decoration samt Unterarten, text-shadow und -webkit-text-stroke/-fill; background-image wird ignoriert.",
   "art": "artikel"
  },
  {
   "seite": "WebKit Bug 282027",
   "url": "https://bugs.webkit.org/show_bug.cgi?id=282027",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: In Safari wirken text-underline-offset und text-decoration-thickness in ::highlight() nicht (Status NEW, zuletzt geändert 02.06.2026). Deshalb Unterstreichung nur als Zusatz.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "MDN: CSS Custom Highlight API",
   "url": "https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API"
  },
  {
   "titel": "MDN: HighlightRegistry",
   "url": "https://developer.mozilla.org/docs/Web/API/HighlightRegistry"
  },
  {
   "titel": "W3C: CSS Custom Highlight API Level 1",
   "url": "https://www.w3.org/TR/css-highlight-api-1/"
  }
 ],
 "kombinierbar_mit": [
  "faq-seite-suche",
  "akkordeon-hoehe-auto",
  "speisekarte-editorial",
  "download-center-dokumente",
  "lesesatz-text-wrap",
  "kopieren-feedback",
  "anker-landung-markieren",
  "command-palette-und-ki-suche"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/typo-techniken/text-hervorhebung-highlight/",
  "meta": "https://cecodesign.de/lab/fundus/typo-techniken/text-hervorhebung-highlight/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/typo-techniken/text-hervorhebung-highlight/demo"
 },
 "herkunft": {
  "quelldateien": [
   "Recherche Runde 4, 04.11.2026"
  ],
  "pruefnotizen": [
   "Recherche Runde 4: Custom Highlights sind Interop-2026-Schwerpunkt; ::highlight bisher nur nebenbei in faq-seite-suche, akkordeon-hoehe-auto und lesesatz-text-wrap.",
   "Browserstand 05.11.2026: ::highlight() laut MDN Baseline 2026 (neu verfügbar seit März 2026); Firefox seit 140. Safari ignoriert text-underline-offset und text-decoration-thickness im Highlight (WebKit Bug 282027).",
   "Abgrenzung: faq-seite-suche ist die ganze Seite (Kategorien, Direktlinks); dieses Muster ist die Technik für jede Hervorhebung, auch Lesen und verlinkte Stelle."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Suchtreffer, eigene Markierungen und verlinkte Textstellen leuchten im Text einer Apotheke auf, ohne ein einziges <mark> im HTML: Range-Objekte plus ::highlight(), Rückfall <mark>.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "api": "CSS.highlights.set(name, new Highlight(...ranges)); Highlight.priority: treffer-aktiv 2, treffer 1, notiz 0",
   "treffer": "::highlight(treffer) background #F2E19A, color #1A2321 (13 : 1)",
   "treffer_aktiv": "::highlight(treffer-aktiv) background #0D6A62, color #fff, text-decoration underline 2px #fff (Safari ignoriert die Dicke)",
   "notiz": "::highlight(notiz) background #CFE8DD, underline 1px #0D6A62",
   "stelle": "stelle-1 … stelle-4: rgba(242, 225, 154, 1 / .72 / .45 / .2); hält 1600 ms, dann alle 300 ms eine Stufe (::highlight kann keine Transition)",
   "suche": "TreeWalker über h3 und p, Vergleich auf normalisierter Fassung (klein, ohne Akzente, ß → ss) mit Rückweg-Karte auf die Originalstelle; entprellt 120 ms; ab 2 Zeichen",
   "sprung": "range.getBoundingClientRect(), scrollBy auf 30 % Höhe, nur wenn außerhalb 20 bis 80 %",
   "ansage": "aria-live polite „Treffer 2 von 5“, 500 ms verzögert",
   "lesen": "getSelection().getRangeAt(0) → Absatz-Index + Textversatz → localStorage 'salbei-reise-markierungen'; eine Markierung je Absatz",
   "link": "?v=zitat&stelle=absatz:start-ende",
   "rueckfall": "ohne CSS.highlights (oder ?ohne-api): Textknoten splitten, <mark class=hl-…> rückwärts einpacken, vor neuer Suche auspacken + normalize()",
   "schrift": "Funnel Display 620 h1 clamp(2rem, 1.3rem + 3vw, 3.4rem), Funnel Sans 17 px, Geist Mono Labels",
   "farben": "#FAFAF8 Grund, #1A2321 Text, #E0ECE8 Salbei-Fläche, #0D6A62 Petrol, #0F3B3A Dunkel"
  },
  "ausloeser": "klick",
  "touch": "Suchtafel klebt oben, Vor und Zurück als 44-px-Knöpfe, Vorschläge ausgeblendet. Lesen: Knopf „Auswahl markieren“ erscheint unten fest (60 px über dem Rand), nur solange eine Auswahl besteht, damit er nicht mit dem System-Menü kollidiert.",
  "reduziert": "Sprung zum Treffer ohne Gleiten; die verlinkte Stelle bleibt markiert, bis man „Markierung entfernen“ wählt; Band ohne Einblenden.",
  "korrekturen": {},
  "geprueft": "05.11.2026",
  "notiz": "Welt: Rezept apotheke-vor-ort, erfundene Salbei-Apotheke am Altmarkt in Löbau. Funnel Display/Sans, Salbei und Petrol, Marker-Gelb nur für Treffer. Suche über sechs Leistungen, Lesen und verlinkte Stelle in einem Ratgeber „Reiseapotheke“. ?ohne-api zeigt den <mark>-Rückfall zum Vergleich. Browserstand 05.11.2026: ::highlight laut MDN Baseline 2026 (seit März 2026), Firefox seit 140; WebKit Bug 282027 (underline-offset/thickness). Vorführung: tippt „Blutdruck“, springt durch Treffer, dann „Termin“; Lesen markiert zwei Stellen; Verlinkt zeigt die Ankunft mit Abklingen. Abgrenzung: faq-seite-suche ist die ganze FAQ-Seite. Selbsturteil 4.",
  "varianten": [
   {
    "id": "suche",
    "name": "Suchtreffer",
    "wann": "FAQ, Leistungslisten, Speisekarte, Download-Center: Suche, die im Text markiert statt nur zu filtern.",
    "werte": {
     "highlights": "treffer + treffer-aktiv",
     "bedienung": "Enter / Umschalt+Enter / Esc, Vor- und Zurück-Knöpfe, Vorschläge"
    }
   },
   {
    "id": "lesen",
    "name": "Markieren beim Lesen",
    "wann": "Ratgeber, Anleitungen, Kursunterlagen: Leser merken sich Stellen auf dem Gerät.",
    "werte": {
     "highlights": "notiz",
     "speicher": "localStorage, Liste mit Springen und Entfernen"
    }
   },
   {
    "id": "zitat",
    "name": "Verlinkte Stelle",
    "wann": "Geteilte Links auf eine Passage (Presse, Kundenservice, Rechtstexte): Ankunft mit Hervorhebung, die abklingt.",
    "werte": {
     "highlights": "stelle-1 … stelle-4",
     "ablauf": "1600 ms halten, 4 × 300 ms abklingen",
     "band": "sticky Hinweis „Sie wurden auf eine Textstelle verlinkt“ mit Entfernen"
    }
   }
  ]
 }
}
