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 verfügbar ist. Außerdem wird erläutert, was wir mit „CSS-in-JS“ meinen und wie es sich von regulärem CSS-Code unterscheidet, der schon seit Längerem von den Entwicklertools unterstützt wird.

Was ist CSS-in-JS?

Die Definition von CSS-in-JS ist ziemlich vage. Im Großen und Ganzen ist es ein Ansatz zum Verwalten von CSS-Code mit JavaScript. Dies könnte beispielsweise bedeuten, dass der CSS-Inhalt mithilfe von JavaScript definiert und die endgültige CSS-Ausgabe in der App generiert wird.

Im Zusammenhang mit Entwicklertools bedeutet „CSS-in-JS“, dass die CSS-Inhalte mithilfe von CSSOM APIs in die Seite eingeschleust werden. Reguläres CSS wird mithilfe von <style>- oder <link>-Elementen eingeschleust und hat eine statische Quelle (z.B. einen DOM-Knoten oder eine Netzwerkressource). CSS-in-JS hingegen hat häufig 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 verwenden (z.B. styled-component, Emotion, JSS), kann die Bibliothek je nach Entwicklungsmodus und Browser Stile über CSSOM APIs einschleusen.

Sehen wir uns einige Beispiele an, wie Sie ein Stylesheet mithilfe der CSSOM API einfügen können, ähnlich wie 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 gänzlich 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 (Stile). Im Bereich Stile sehen Sie, welche Regeln für ein bestimmtes Element gelten. Außerdem können Sie die Regeln bearbeiten und die Änderungen auf der Seite in Echtzeit sehen.

Vor dem letzten Jahr war die Unterstützung für CSS-Regeln, die mithilfe der CSSOM APIs geändert wurden, eher eingeschränkt: Sie konnten nur die angewendeten Regeln sehen, aber nicht bearbeiten. Letztes Jahr wollten wir vor allem CSS-in-JS-Regeln mithilfe des Bereichs "Styles" bearbeiten. Manchmal nennen wir CSS-in-JS-Stile auch "built", um anzugeben, dass sie mit Web APIs erstellt wurden.

Sehen wir uns genauer an, wie die Stilbearbeitung in den Entwicklertools funktioniert.

Mechanismus zur Stilbearbeitung in den Entwicklertools

Mechanismus zur Stilbearbeitung 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 Entwicklertools-Front-End zusätzliche Informationen zur untersuchten Seite abrufen kann.

Wenn CSS.getMatchedStylesForNode aufgerufen wird, identifiziert es alle Stylesheets im Dokument und parst sie mit dem CSS-Parser des Browsers. Anschließend wird ein Index erstellt, der jede CSS-Regel mit einer Position in der Stylesheet-Quelle verknüpft.

Sie fragen sich vielleicht, warum das CSS noch einmal geparst werden muss. Das Problem hierbei ist, dass der Browser selbst aus Leistungsgründen sich nicht mit den Quellpositionen von CSS-Regeln befasst 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, aber wir möchten, dass die Entwicklertools-Nutzer Zugriff auf die Quellpositionen haben. Dieser Wiederholungsansatz deckt beide Anwendungsfälle mit minimalen Nachteilen ab.

Als Nächstes fordert die CSS.getMatchedStylesForNode-Implementierung die Stil-Engine des Browsers auf, CSS-Regeln bereitzustellen, die mit dem jeweiligen Element übereinstimmen. Und schließlich verknüpft die Methode die von der Stil-Engine zurückgegebenen Regeln mit dem Quellcode und liefert eine strukturierte Antwort zu CSS-Regeln, damit die Entwicklertools wissen, welcher Teil der Regel der Selektor oder die Eigenschaften ist. Damit können die Entwicklertools den Selektor und die Eigenschaften unabhängig bearbeiten.

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

Im Backend aktualisiert die Entwicklertools das Ziel-Stylesheet, wenn der Bearbeitungsaufruf verarbeitet wird. Außerdem wird die Kopie der von ihr verwalteten Stylesheet-Quelle aktualisiert und die Quellpositionen für die aktualisierte Regel werden aktualisiert. Als Reaktion auf den Bearbeitungsaufruf erhält das Entwicklertools-Front-End die aktualisierten Positionen für das gerade aktualisierte Textfragment zurück.

Das erklärt, warum das Bearbeiten von CSS-in-JS in den Entwicklertools nicht von Anfang an funktioniert hat: Bei CSS-in-JS ist keine tatsächliche Quelle gespeichert und die CSS-Regeln sind in CSSOM-Datenstrukturen im Arbeitsspeicher des Browsers verfügbar.

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

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

Der erste Schritt besteht darin, den Ausgangstext zu erstellen. Im Stilmodul des Browsers werden die CSS-Regeln in der Klasse CSSStyleSheet gespeichert. Bei dieser Klasse können Sie, wie bereits erläutert, Instanzen aus JavaScript erstellen. Der Code zum Erstellen des Quelltexts 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();
}

Er durchläuft die Regeln in einer CSSStyleSheet-Instanz und erstellt daraus einen einzelnen String. Diese Methode wird aufgerufen, wenn eine Instanz der Klasse InspectorStyleSheet erstellt wird. 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, das CollectStyleSheetRules intern aufruft. CSSOMStyleSheetText wird aufgerufen, wenn das Stylesheet nicht inline oder kein Ressourcen-Stylesheet ist. Diese beiden Snippets ermöglichen bereits eine grundlegende Bearbeitung der Stylesheets, die mit dem Konstruktor new CSSStyleSheet() 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. Um diesen Fall zu handhaben, führen wir eine Methode ein, mit der diese zusätzlichen Regeln im Quelltext zusammengeführt werden können. Hier spielt die Reihenfolge eine Rolle, da CSS-Regeln in der Mitte des ursprünglichen Quelltexts 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, die zu folgender Reihenfolge der Regeln führten: .rule0, .rule1, .rule2, .rule3, .rule4. Der Quelltext nach der Zusammenführung sollte wie folgt aussehen:

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

Die Beibehaltung der ursprünglichen Kommentare und Einzüge ist wichtig für den Bearbeitungsprozess, da die Positionen der Regeln im Ausgangstext präzise sein müssen.

Ein weiterer Vorteil von 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 übereinstimmen, funktioniert die Bearbeitung nicht. Dafür haben wir eine sogenannte Prüfung eingeführt, mit der der Browser den Back-End-Teil der Entwicklertools benachrichtigen kann, wenn ein Stylesheet geändert wird. Geänderte Stylesheets werden dann beim nächsten Aufruf von CSS.getMatchingStylesForNode synchronisiert.

Mit all diesen Teilen funktioniert die CSS-in-JS-Bearbeitung bereits, aber wir wollten die Benutzeroberfläche verbessern, damit angezeigt wird, ob ein Stylesheet erstellt wurde. Wir haben dem CDP-Element CSS.CSSStyleSheetHeader ein neues Attribut namens isConstructed hinzugefügt, das vom Front-End verwendet wird, um die Quelle einer CSS-Regel korrekt anzuzeigen:

Konstruierbares Stylesheet

Ergebnisse

Um unsere Geschichte zusammenzufassen, haben wir uns die relevanten Anwendungsfälle im Zusammenhang mit CSS-in-JS angesehen, die von den Entwicklertools nicht unterstützt wurden, und die Lösung für diese Anwendungsfälle durchgegangen. Das Interessante an dieser Implementierung besteht darin, dass wir die vorhandenen Funktionen nutzen konnten, indem wir CSSOM-CSS-Regeln mit einem regulären Quelltext versehen, sodass die Stilbearbeitung in den Entwicklertools nicht komplett neu gestaltet werden muss.

Weitere Hintergrundinformationen finden Sie in unserem Designvorschlag oder im Chromium-Tracking-Fehler, in dem alle zugehörigen Patches beschrieben werden.

Vorschaukanäle herunterladen

Sie können Canary, Dev oder Beta als Standardbrowser für die Entwicklung verwenden. Über diese Vorschaukanäle erhältst du Zugriff auf die neuesten Entwicklertools, kannst hochmoderne Webplattform-APIs testen und Probleme auf deiner Website erkennen, bevor deine Nutzer es tun.

Kontaktaufnahme mit dem Team für Chrome-Entwicklertools

Mit den folgenden Optionen kannst du die neuen Funktionen und Änderungen des Beitrags oder andere Aspekte der Entwicklertools besprechen.

  • Senden Sie uns über crbug.com einen Vorschlag oder Feedback.
  • Melde ein Problem mit den Entwicklertools über Weitere Optionen   Mehr   > Hilfe > Probleme mit den Entwicklertools melden in den Entwicklertools.
  • Twittern Sie unter @ChromeDevTools.
  • Hinterlasse Kommentare in den YouTube-Videos mit den Neuerungen in den Entwicklertools oder in YouTube-Videos mit Tipps zu den Entwicklertools.