Unterstützung von CSS in JS in den Entwicklertools

Alex Rudenko
Alex Rudenko

In diesem Artikel geht es um die Unterstützung von CSS-in-JS in den Entwicklertools, die seit Chrome 85 eingeführt wurden, und im Allgemeinen, was wir unter CSS-in-JS verstehen und wie sie sich von regulärem CSS-Code unterscheidet, der schon lange von den Entwicklertools unterstützt wird.

Was ist CSS-in-JS?

Die Definition von CSS-in-JS ist vage. Im Großen und Ganzen handelt es sich um einen Ansatz zur Verwaltung von CSS-Code mithilfe von JavaScript. Es kann beispielsweise bedeuten, dass der CSS-Inhalt mit JavaScript definiert wird und die endgültige CSS-Ausgabe automatisch von der App generiert wird.

Im Kontext der Entwicklertools bedeutet „CSS-in-JS“, dass CSS-Inhalte mithilfe von CSSOM APIs in die Seite eingeschleust werden. Reguläres CSS wird mit <style>- oder <link>-Elementen eingeschleust und hat eine statische Quelle (z.B. einen DOM-Knoten oder eine Netzwerkressource). Im Gegensatz dazu verfügt CSS-in-JS häufig über keine statische Quelle. Ein Sonderfall hier ist, dass der Inhalt eines <style>-Elements mithilfe der CSSOM API aktualisiert werden kann, wodurch die Quelle nicht mit dem tatsächlichen CSS-Stylesheet synchron ist.

Wenn Sie eine CSS-in-JS-Bibliothek (z.B. styled-component, Emotion, JSS) verwenden, kann die Bibliothek Stile je nach Entwicklungsmodus und Browser mithilfe von CSSOM APIs im Hintergrund einschleusen.

Sehen wir uns einige Beispiele an, die zeigen, wie Sie ein Stylesheet mit der CSSOM API einfügen können, ähnlich wie bei CSS-in-JS-Bibliotheken.

// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

Sie können auch ein völlig neues Stylesheet erstellen:

// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];

CSS-Unterstützung in den Entwicklertools

Die am häufigsten verwendete Funktion in den Entwicklertools ist der Bereich Styles. Im Bereich Stile sehen Sie, welche Regeln für ein bestimmtes Element gelten, und können die Regeln bearbeiten und die Änderungen auf der Seite in Echtzeit sehen.

Vor dem letzten Jahr wurden CSS-Regeln, die mit CSSOM APIs geändert wurden, eher eingeschränkt unterstützt: Sie konnten nur die angewendeten Regeln sehen, aber nicht bearbeiten. Im letzten Jahr hatten wir vor allem das Ziel, CSS-in-JS-Regeln über den Bereich „Styles“ zu bearbeiten. Manchmal werden CSS-in-JS-Stile auch "constructed" genannt, um anzuzeigen, dass sie mithilfe von Web-APIs erstellt wurden.

Sehen wir uns die Bearbeitung von Stilen in den Entwicklertools genauer an.

Bearbeitungstechnik für Stil in den Entwicklertools

Bearbeitungstechnik für Stil in den Entwicklertools

Wenn Sie in den Entwicklertools ein Element auswählen, wird der Bereich Styles angezeigt. Im Bereich Styles wird der CDP-Befehl CSS.getMatchedStylesForNode ausgegeben, um CSS-Regeln abzurufen, die für das Element gelten. CDP steht für „Chrome DevTools Protocol“ und ist eine API, mit der das DevTools-Front-End zusätzliche Informationen zur untersuchten Seite abrufen kann.

Beim Aufruf identifiziert CSS.getMatchedStylesForNode alle Stylesheets im Dokument und parst sie mithilfe des CSS-Parsers des Browsers. Anschließend wird ein Index erstellt, der jede CSS-Regel einer Position in der Stylesheet-Quelle zuordnet.

Sie fragen sich vielleicht, warum der CSS-Code noch einmal geparst werden muss. Das Problem hier besteht darin, dass der Browser aus Leistungsgründen die Quellpositionen von CSS-Regeln nicht berücksichtigt und diese daher nicht speichert. Die Entwicklertools benötigen jedoch die Quellpositionen, um die CSS-Bearbeitung zu unterstützen. Wir möchten nicht, dass reguläre Chrome-Nutzer die Leistungseinbußen zahlen müssen, aber wir möchten, dass Nutzer der Entwicklertools Zugriff auf die Quellpositionen haben. Dieser Ansatz der Neuanalyse deckt beide Anwendungsfälle ab und hat nur minimale Nachteile.

Als Nächstes fordert die CSS.getMatchedStylesForNode-Implementierung die Stil-Engine des Browsers auf, CSS-Regeln bereitzustellen, die mit dem angegebenen Element übereinstimmen. Schließlich verknüpft die Methode die von der Stil-Engine zurückgegebenen Regeln mit dem Quellcode und stellt eine strukturierte Antwort zu CSS-Regeln bereit, sodass die Entwicklertools wissen, welcher Teil der Regel der Selektor bzw. die Eigenschaften ist. Die Entwicklertools können die Auswahl und die Properties unabhängig voneinander bearbeiten.

Kommen wir nun zur Bearbeitung. Denken Sie daran, dass CSS.getMatchedStylesForNode Quellpositionen für jede Regel zurückgibt. Das ist entscheidend für die Bearbeitung. Wenn Sie eine Regel ändern, gibt die Entwicklertools einen weiteren CDP-Befehl aus, mit dem die Seite tatsächlich aktualisiert wird. Der Befehl enthält die ursprüngliche Position des Fragments der Regel, die aktualisiert wird, sowie den neuen Text, mit dem das Fragment aktualisiert werden soll.

Im Back-End aktualisiert die Entwicklertools bei der Verarbeitung des Bearbeitungsaufrufs das Ziel-Stylesheet. Außerdem wird die Kopie der Stylesheet-Quelle aktualisiert, die von ihr verwaltet wird, und die Quellpositionen für die aktualisierte Regel werden aktualisiert. Als Antwort auf den Bearbeitungsaufruf erhält das Front-End der Entwicklertools die aktualisierten Positionen für das gerade aktualisierte Textfragment zurück.

Dies erklärt, warum das Bearbeiten von CSS-in-JS in den Entwicklertools nicht von Anfang an funktioniert hat: CSS-in-JS hat nirgendwo eine tatsächliche Quelle gespeichert und die CSS-Regeln befinden sich im Arbeitsspeicher des Browsers in CSSOM-Datenstrukturen.

Unterstützung für CSS-in-JS hinzugefügt

Um die Bearbeitung von CSS-in-JS-Regeln zu unterstützen, haben wir uns für die beste Lösung entschieden, eine Quelle für erstellte Stylesheets zu erstellen, die mit dem oben beschriebenen Mechanismus bearbeitet werden kann.

Der erste Schritt besteht darin, den Ausgangstext zu erstellen. Die Stil-Engine des Browsers speichert die CSS-Regeln in der Klasse CSSStyleSheet. Diese Klasse ist die Klasse, deren Instanzen Sie, wie zuvor erläutert, aus JavaScript erstellen können. Der Code zum Erstellen des Quelltextes lautet wie folgt:

String InspectorStyleSheet::CollectStyleSheetRules() {
  StringBuilder builder;
  for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
    builder.Append(page_style_sheet_->item(i)->cssText());
    builder.Append('\n');
  }
  return builder.ToString();
}

Sie durchläuft die Regeln einer CSSStyleSheet-Instanz und erstellt daraus einen einzelnen String. Diese Methode wird beim Erstellen einer Instanz der InspectorStyleSheet-Klasse aufgerufen. Die InspectorStyleSheet-Klasse umschließt eine CSSStyleSheet-Instanz und extrahiert zusätzliche Metadaten, die von den Entwicklertools benötigt werden:

void InspectorStyleSheet::UpdateText() {
  String text;
  bool success = InspectorStyleSheetText(&text);
  if (!success)
    success = InlineStyleSheetText(&text);
  if (!success)
    success = ResourceStyleSheetText(&text);
  if (!success)
    success = CSSOMStyleSheetText(&text);
  if (success)
    InnerSetText(text, false);
}

In diesem Snippet sehen wir CSSOMStyleSheetText, die intern CollectStyleSheetRules aufruft. CSSOMStyleSheetText wird aufgerufen, wenn das Stylesheet nicht inline oder kein Ressourcen-Stylesheet ist. Im Grunde ermöglichen diese beiden Snippets bereits eine grundlegende Bearbeitung der Stylesheets, die mit dem new CSSStyleSheet()-Konstruktor erstellt werden.

Ein Sonderfall sind die mit einem <style>-Tag verknüpften Stylesheets, die mithilfe der CSSOM API geändert wurden. In diesem Fall enthält das Stylesheet den Quelltext und zusätzliche Regeln, die in der Quelle nicht vorhanden sind. Dazu führen wir eine Methode ein, mit der diese zusätzlichen Regeln im Ausgangstext zusammengeführt werden können. Hier ist die Reihenfolge wichtig, da CSS-Regeln in der Mitte des ursprünglichen Ausgangstexts eingefügt werden können. Angenommen, das ursprüngliche <style>-Element enthielt den folgenden Text:

/* comment */
.rule1 {}
.rule3 {}

Dann fügte die Seite mithilfe der JS API einige neue Regeln ein, wodurch die folgende Regelreihenfolge erzeugt wurde: .rule0, .rule1, .rule2, .rule3,..rule4. Nach dem Zusammenführungsvorgang sollte der Quelltext wie folgt aussehen:

.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}

Das Beibehalten der ursprünglichen Kommentare und des Einzugs ist für den Bearbeitungsprozess wichtig, da die Positionen des Quelltextes der Regeln präzise sein müssen.

Ein weiterer Aspekt bei CSS-in-JS-Stylesheets ist, dass sie jederzeit von der Seite geändert werden können. Wenn die tatsächlichen CSSOM-Regeln nicht mit der Textversion synchron wären, funktioniert die Bearbeitung nicht. Dazu haben wir eine sogenannte Prüfung eingeführt, mit der der Browser den Back-End-Teil der Entwicklertools benachrichtigen kann, wenn ein Stylesheet verändert wird. Geänderte Stylesheets werden dann während des nächsten Aufrufs von CSS.getCompatibleStylesForNode synchronisiert.

Nachdem alle diese Elemente vorhanden sind, funktioniert die CSS-in-JS-Bearbeitung bereits. Wir wollten jedoch die Benutzeroberfläche verbessern, um anzuzeigen, ob ein Stylesheet erstellt wurde. Wir haben CSS.CSSStyleSheetHeader des CDP ein neues Attribut namens isConstructed hinzugefügt, das vom Front-End verwendet wird, um die Quelle einer CSS-Regel korrekt anzuzeigen:

Konstruktierbares Stylesheet

Ergebnisse

Wir haben uns die relevanten Anwendungsfälle im Zusammenhang mit CSS-in-JS angesehen, die von den Entwicklertools nicht unterstützt wurden, und wir haben die entsprechende Lösung durchgegangen. Der interessante Teil dieser Implementierung ist, dass wir die vorhandenen Funktionen nutzen konnten, indem wir CSSOM-CSS-Regeln in einen regulären Quelltext umwandeln, sodass wir die Stilbearbeitung in den Entwicklertools nicht komplett neu gestalten müssen.

Weitere Informationen findest du in unserem Designvorschlag oder in dem Tracking-Fehler in Chromium, in dem alle zugehörigen Patches aufgeführt sind.

Vorschaukanäle herunterladen

Du kannst Chrome Canary, Dev oder Beta als Standardbrowser für die Entwicklung verwenden. Mit diesen Vorschaukanälen erhalten Sie Zugriff auf die neuesten Funktionen der Entwicklertools, können bahnbrechende Webplattform-APIs testen und Probleme auf Ihrer Website erkennen, noch bevor Ihre Nutzer dies tun.

Chrome-Entwicklertools-Team kontaktieren

Verwende die folgenden Optionen, um die neuen Funktionen und Änderungen im Beitrag oder andere Themen im Zusammenhang mit den Entwicklertools zu besprechen.

  • Sende uns über crbug.com einen Vorschlag oder Feedback.
  • Wenn du ein Problem mit den Entwicklertools melden möchtest, klicke in den Entwicklertools auf Weitere Optionen   Mehr   > Hilfe > Probleme mit Entwicklertools melden.
  • Senden Sie einen Tweet an @ChromeDevTools.
  • Hinterlasse Kommentare unter YouTube-Videos oder YouTube-Videos mit Tipps zu DevTools.