Das Styling von Textbereichen in Software ist eine sehr nützliche Funktion. Glücklicherweise können wir uns auf die CSS Custom Highlight API freuen, da sie die Zukunft des Stylings von Textbereichen im Web darstellt.

Ein Beispiel: Wenn Sie jemals Textbearbeitungssoftware wie Google Docs, Word oder Dropbox Paper verwendet haben, sehen Sie, dass diese Rechtschreib- und Grammatikfehler erkennen und sie mit kleinen wellenförmigen Unterstreichungen hervorheben, um Aufmerksamkeit zu erregen. Code-Editoren wie VS Code tun dasselbe für Codefehler.

Ein weiterer sehr häufiger Anwendungsfall für das Hervorheben von Text ist die Suche und Hervorhebung, bei der Sie ein Texteingabefeld erhalten und das Tippen darin übereinstimmende Ergebnisse auf der Seite sucht und diese hervorhebt. Versuchen Sie, jetzt Strg/⌘ + F in Ihrem Webbrowser zu drücken und geben Sie einen Text aus diesem Artikel ein.

Der Browser selbst kümmert sich oft um diese Styling-Situationen. Bearbeitbare Bereiche (wie ein <textarea>) erhalten automatisch Rechtschreibwellenlinien. Der Suchbefehl hebt gefundene Texte automatisch hervor.
Aber was ist, wenn wir diese Art von Styling selbst machen wollen? Dies im Web zu tun, ist seit langem ein häufiges Problem. Es hat wahrscheinlich vielen Leuten viel mehr Zeit gekostet, als es hätte tun sollen.
Dies ist kein einfaches Problem. Wir umhüllen den Text nicht nur mit einem <span> mit einer Klasse und wenden etwas CSS an. Tatsächlich erfordert dies die Fähigkeit, mehrere Textbereiche korrekt über einen beliebig komplexen DOM-Baum hervorzuheben, und möglicherweise auch über die Grenzen von DOM-Elementen hinweg.
Es gibt zwei gängige Lösungen dafür, darunter
- Styling von Pseudo-Elementen für Textbereiche und
- Erstellen eines eigenen Text Hervorhebungssystems.
Wir werden sie zuerst überprüfen und dann die bevorstehende CSS Custom Highlight API betrachten, die alles ändern kann. Aber wenn Sie
Mögliche Lösung #1: Stilbare Textbereiche
Wahrscheinlich der bekannteste stilbare Textbereich ist die Benutzerauswahl. Wenn Sie mit Ihrem Zeigegerät einen Textabschnitt auf einer Webseite auswählen, wird automatisch ein Selection-Objekt erstellt. Tatsächlich versuchen Sie, Text auf dieser Seite jetzt auszuwählen, und führen Sie dann document.getSelection() in der DevTools-Konsole aus. Sie sollten Informationen über den Speicherort des ausgewählten Texts sehen.

Es stellt sich heraus, dass Sie auch programmatisch von JavaScript aus eine Textauswahl erstellen können. Hier ist ein Beispiel
// First, create a Range object.
const range = new Range();
// And set its start and end positions.
range.setStart(parentNode, startOffset);
range.setEnd(parentNode, endOffset);
// Then, set the current selection to this range.
document.getSelection().removeAllRanges();
document.getSelection().addRange(range);
Das letzte Puzzleteil ist das Styling dieses Bereichs. CSS hat ein Pseudo-Element namens ::selection, um genau das zu tun, und es wird in allen Browsern unterstützt.
::selection {
background-color: #f06;
color: white;
}
Hier ist ein Beispiel, das diese Technik verwendet, um alle Wörter auf einer Seite nacheinander hervorzuheben
Zusätzlich zum ::selection-Pseudo-Element gibt es eine Reihe weiterer Pseudo-Elemente
::target-textwählt den Text aus, zu dem in Browsern gescrollt wurde, die das Scroll-to-Text-Feature unterstützen. (MDN)::spelling-errorwählt Text aus, der vom Browser als Rechtschreibfehler gekennzeichnet ist. (MDN)::grammar-errorwählt Text aus, der vom Browser als Grammatikfehler gekennzeichnet ist. (MDN)
Leider ist die Browserunterstützung hier nicht großartig, und obwohl diese Bereiche jeweils für sich nützlich sind, können sie nicht zum Styling benutzerdefinierter Textteile verwendet werden – nur vom Browser vordefinierte.
Die Textauswahl des Benutzers ist also gut, weil sie relativ einfach zu implementieren ist und die DOM der Seite nicht verändert. Tatsächlich sind Range-Objekte im Wesentlichen Koordinaten von Segmenten auf der Seite, anstatt HTML-Elemente, die erstellt werden müssen, um zu existieren.
Ein wesentlicher Nachteil ist jedoch, dass die Erstellung einer Auswahl die vom Benutzer bereits manuell getroffene Auswahl zurücksetzt. Versuchen Sie, Text in der obigen Demo auszuwählen, um dies zu testen. Sie werden sehen, wie er verschwindet, sobald der Code die Auswahl an eine andere Stelle verschiebt.
Mögliche Lösung #2: Benutzerdefiniertes Hervorhebungssystem
Diese zweite Lösung ist so ziemlich das Einzige, was Sie tun können, wenn die Verwendung des Selection-Objekts für Sie nicht ausreicht. Diese Lösung dreht sich darum, alles selbst zu tun und JavaScript zu verwenden, um neue HTML-Elemente in den DOM einzufügen, wo Sie die Hervorhebung anzeigen möchten.
Leider bedeutet dies viel mehr JavaScript, das geschrieben und gepflegt werden muss, ganz zu schweigen davon, dass der Browser das Layout der Seite bei jeder Änderung der Hervorhebung neu erstellen muss. Außerdem gibt es komplizierte Randfälle, zum Beispiel, wenn Sie einen Textabschnitt hervorheben möchten, der sich über mehrere DOM-Elemente erstreckt.

Interessanterweise haben CodeMirror und Monaco (die JavaScript-Texteditor-Bibliothek, die VS Code antreibt) ihre eigene Hervorhebungslogik. Sie verwenden einen leicht anderen Ansatz, bei dem die Hervorhebungen in einem separaten Teil des DOM-Baums enthalten sind. Die Textzeilen und die hervorgehobenen Segmente werden an zwei verschiedenen Stellen im DOM gerendert, die dann übereinander positioniert werden. Wenn Sie den DOM-Unterbaum inspizieren, der den Text enthält, gibt es keine Hervorhebungen. Auf diese Weise können die Hervorhebungen neu gerendert werden, ohne die Textzeilen zu beeinträchtigen und neue Elemente in ihnen einzuführen.
Insgesamt scheint eine browsergestützte Hervorhebungsfunktion zu fehlen. Etwas, das helfen würde, all diese Nachteile zu lösen (keine Beeinträchtigung der Benutzerauswahl, Unterstützung für Mehrfachauswahl, einfacher Code) und schneller als benutzerdefinierte Lösungen wäre.
Glücklicherweise ist das, worüber wir hier sprechen!
Einführung in die CSS Custom Highlight API
Die CSS Custom Highlight API ist eine neue W3C-Spezifikation (derzeit im Working Draft-Status), die es ermöglicht, beliebige Textbereiche aus JavaScript zu stylen! Der Ansatz hier ist dem Benutzer-Textauswahl-Technik, die wir zuvor besprochen haben, sehr ähnlich. Sie gibt Entwicklern eine Möglichkeit, aus JavaScript beliebige Bereiche zu erstellen und sie dann mit CSS zu stylen.
Erstellen von Textbereichen
Der erste Schritt ist die Erstellung der Textbereiche, die Sie hervorheben möchten, was mit einem Range in JavaScript erfolgen kann. So wie wir es beim Einstellen der aktuellen Auswahl getan haben
const range = new Range();
range.setStart(parentNode, startOffset);
range.setEnd(parentNode, endOffset);
Es ist erwähnenswert, dass die Methoden setStart und setEnd unterschiedlich funktionieren, je nachdem, ob der als erstes Argument übergebene Knoten ein Textknoten ist oder nicht. Für Textknoten entspricht der Offset der Anzahl der Zeichen innerhalb des Knotens. Für andere Knoten entspricht der Offset der Anzahl der Kindknoten innerhalb des Elternknotens.
Ebenfalls erwähnenswert ist, dass setStart und setEnd nicht die einzigen Möglichkeiten sind, den Anfang und das Ende eines Bereichs zu beschreiben. Schauen Sie sich die anderen Methoden der Range-Klasse an, um weitere Optionen zu sehen.
Erstellen von Hervorhebungen
Der zweite Schritt besteht darin, Highlight-Objekte für die im letzten Schritt erstellten Bereiche zu erstellen. Ein Highlight-Objekt kann einen oder mehrere Ranges aufnehmen. Wenn Sie also mehrere Textstücke auf genau die gleiche Weise hervorheben möchten, sollten Sie wahrscheinlich ein einzelnes Highlight-Objekt erstellen und es mit allen Ranges initialisieren, die diesen Textstücken entsprechen.
const highlight = new Highlight(range1, range2, ..., rangeN);
Sie können aber auch so viele Highlight-Objekte erstellen, wie Sie benötigen. Wenn Sie beispielsweise einen kollaborativen Texteditor erstellen, bei dem jeder Benutzer eine andere Textfarbe erhält, können Sie pro Benutzer ein Highlight-Objekt erstellen. Jedes Objekt kann dann unterschiedlich gestylt werden, wie wir als nächstes sehen werden.
Registrieren von Hervorhebungen
Highlight-Objekte allein tun nichts. Sie müssen zuerst in einem sogenannten Hervorhebungsregister registriert werden. Dies geschieht über die CSS Highlights API. Das Register funktioniert wie eine Map, in der Sie neue Hervorhebungen registrieren können, indem Sie ihnen Namen geben, sowie Hervorhebungen entfernen (oder sogar das gesamte Register löschen).
So registriert man eine einzelne Hervorhebung.
CSS.highlights.set('my-custom-highlight', highlight);
Wobei my-custom-highlight der von Ihnen gewählte Name und highlight ein Highlight-Objekt ist, das im letzten Schritt erstellt wurde.
Styling von Hervorhebungen
Der letzte Schritt ist das eigentliche Styling der registrierten Hervorhebungen. Dies geschieht mit dem neuen CSS ::highlight()-Pseudo-Element, unter Verwendung des Namens, den Sie bei der Registrierung des Highlight-Objekts gewählt haben (der in unserem obigen Beispiel my-custom-highlight ist).
::highlight(my-custom-highlight) {
background-color: yellow;
color: black;
}
Es ist erwähnenswert, dass, ähnlich wie bei ::selection, nur eine Teilmenge von CSS-Eigenschaften mit dem ::highlight()-Pseudo-Element verwendet werden kann
background-colorcaret-colorcolorcursorfillstrokestroke-widthtext-decoration(die wahrscheinlich nur in Version 2 der Spezifikation unterstützt wird)text-shadow
Aktualisieren von Hervorhebungen
Es gibt mehrere Möglichkeiten, hervorgehobenen Text auf der Seite zu aktualisieren.
Sie können beispielsweise das Hervorhebungsregister komplett mit CSS.highlights.clear() leeren und dann von vorne beginnen. Oder Sie können die zugrundeliegenden Bereiche aktualisieren, ohne eines der Objekte neu erstellen zu müssen. Verwenden Sie dazu erneut die Methoden range.setStart und range.setEnd (oder eine der anderen Range-Methoden), und die Hervorhebungen werden vom Browser neu gezeichnet.
Aber das Highlight-Objekt funktioniert wie ein JavaScript Set, was bedeutet, dass Sie auch neue Range-Objekte zu einem bestehenden Highlight mit highlight.add(newRange) hinzufügen oder einen Range mit highlight.delete(existingRange) entfernen können.
Drittens können Sie auch spezifische Highlight-Objekte aus dem CSS.highlights-Register hinzufügen oder entfernen. Da diese API wie eine JavaScript Map funktioniert, können Sie set und delete verwenden, um die aktuell registrierten Highlights zu aktualisieren.
Browser-Unterstützung
Die Spezifikation für die CSS Custom Highlight API ist relativ neu und ihre Implementierung in Browsern noch unvollständig. Obwohl dies eine sehr nützliche Ergänzung zur Web-Plattform sein wird, ist sie noch nicht für den produktiven Einsatz bereit.
Das Microsoft Edge-Team implementiert die CSS Custom Highlight API derzeit in Chromium. Tatsächlich kann das Feature bereits jetzt in Canary-Versionen genutzt werden, indem das Flag "Experimental Web Platform features" (unter about:flags) aktiviert wird. Es gibt derzeit keinen festen Plan, wann das Feature in Chrome, Edge und anderen Chromium-basierten Browsern veröffentlicht wird, aber es ist sehr nah dran.
Die API wird auch in Safari 99+ unterstützt, jedoch hinter einem experimentellen Flag (Develop → Experimental Features → Highlight API), und die Schnittstelle ist dort etwas anders, da sie StaticRange-Objekte verwendet.
Firefox unterstützt die API noch nicht, aber Sie können Mozillas Position dazu lesen für weitere Informationen.
Demo
Apropos Microsoft Edge, sie haben eine Demo eingerichtet, mit der Sie die CSS Custom Highlight API ausprobieren können. Bevor Sie die Demo ausprobieren, stellen Sie sicher, dass Sie entweder Chrome oder Edge Canary mit dem Flag "Experimental Web Platform features" auf der Seite about:flags verwenden.
/button Demo ansehen
Die Demo verwendet die Custom Highlight API, um Textbereiche auf der Seite basierend auf dem, was Sie in das Suchfeld oben auf der Seite eingeben, hervorzuheben.
Nachdem die Seite geladen ist, ruft JavaScript-Code alle Textknoten auf der Seite ab (mithilfe eines TreeWalker) und wenn der Benutzer in das Suchfeld tippt, durchläuft der Code diese Knoten, bis er Übereinstimmungen findet. Diese Übereinstimmungen werden dann verwendet, um Range-Objekte zu erstellen, die dann mit der Custom Highlight API hervorgehoben werden.
Abschließende Gedanken
Also, ist diese neue browsergestützte Hervorhebungs-API wirklich lohnenswert? Absolut!
Zum einen, auch wenn die CSS Custom Highlight API auf den ersten Blick etwas kompliziert erscheinen mag (d.h. Bereiche erstellen, dann Hervorhebungen, dann registrieren und schließlich stylen), ist sie immer noch viel einfacher, als neue DOM-Elemente erstellen und an den richtigen Stellen einfügen zu müssen.
Noch wichtiger ist, dass Browser-Engines diese Bereiche sehr, sehr schnell stylen können.
Der Grund, warum nur eine Teilmenge von CSS-Eigenschaften mit dem ::highlight()-Pseudo-Element verwendet werden darf, ist, dass die Teilmenge nur Eigenschaften enthält, die der Browser sehr effektiv anwenden kann, ohne das Layout der Seite neu erstellen zu müssen. Das Hervorheben von Textbereichen durch Einfügen neuer DOM-Elemente um sie herum erfordert, dass die Engine viel mehr Arbeit leistet.
Aber glauben Sie mir nicht einfach. Fernando Fiori, der an der API gearbeitet hat, hat diese nette Performance-Vergleichs-Demo erstellt. Auf meinem Computer ist die CSS Custom Highlight API im Durchschnitt 5x schneller als das DOM-basierte Hervorheben.
Mit experimenteller Unterstützung in Chromium und Safari, die bereits vorhanden ist, nähern wir uns etwas, das in der Produktion verwendet werden kann. Ich kann es kaum erwarten, bis die Browser die Custom Highlight API konsistent unterstützen und sehen, welche Funktionen dies freisetzen wird!
Ich warte gespannt darauf! Würden CSS Custom Properties auch für den Hervorhebungsnamen unterstützt, damit wir sie dynamisch stylen könnten (wie im Kollaborationsbeispiel, das Sie erwähnt haben)?
Derzeit erlaubt die Spezifikation nicht die Verwendung von benutzerdefinierten Eigenschaften als Namen in der CSS :highlight()-Pseudo-Klasse. Dynamisches Styling kann jedoch erreicht werden, indem der Name, mit dem das Highlight-Objekt registriert wird, gewechselt wird.
Ich bin so aufgeregt deswegen! Und die Probleme mit dem Hervorheben von Text sind genau die, mit denen ich auch bei meinem Nebenprojekt zu kämpfen habe. Ich hoffe, diese neue API wird bald von allen Browsern unterstützt ✨
Ich bin gespannt darauf, die Verwendung dieser Hervorhebungen über Knotengrenzen hinweg auszuprobieren. Mir ist aufgefallen, dass die Microsoft-Demo nur funktioniert, wenn der hervorzuhebende Text innerhalb eines einzelnen Knotens liegt.
Weiß jemand, ob das funktioniert, um Text in einem <input> oder einer <textarea> hervorzuheben?
@Darren, es scheint nicht mit Textarea und Input zu funktionieren.