Fragen Sie sich, was noch schwieriger ist als die Wahl eines JavaScript-Frameworks? Sie haben es erraten: die Wahl einer CSS-in-JS-Lösung. Warum? Weil es mehr als 50 Bibliotheken gibt, die jeweils einen einzigartigen Satz von Funktionen bieten.
Wir haben 10 verschiedene Bibliotheken getestet, die hier in keiner bestimmten Reihenfolge aufgeführt sind: Styled JSX, styled-components, Emotion, Treat, TypeStyle, Fela, Stitches, JSS, Goober und Compiled. Wir stellten fest, dass, obwohl jede Bibliothek eine vielfältige Palette von Funktionen bietet, viele dieser Funktionen tatsächlich zwischen den meisten anderen Bibliotheken gemeinsam sind.
Anstatt also jede Bibliothek einzeln zu rezensieren, werden wir die Funktionen analysieren, die am meisten hervorstechen. Dies wird uns helfen, besser zu verstehen, welche am besten für einen bestimmten Anwendungsfall geeignet ist.
Hinweis: Wir gehen davon aus, dass Sie, wenn Sie hier sind, bereits mit CSS-in-JS vertraut sind. Wenn Sie einen grundlegenderen Beitrag suchen, können Sie sich „Eine Einführung in CSS-in-JS“ ansehen.
Gemeinsame CSS-in-JS-Funktionen
Die meisten aktiv gepflegten Bibliotheken, die sich mit CSS-in-JS befassen, unterstützen alle folgenden Funktionen, sodass wir sie als de facto betrachten können.
Gekapselte CSS
Alle CSS-in-JS-Bibliotheken generieren eindeutige CSS-Klassennamen, eine Technik, die von CSS Modules eingeführt wurde. Alle Stile sind auf ihre jeweilige Komponente beschränkt und bieten Kapselung, ohne die außerhalb der Komponente definierten Stile zu beeinträchtigen.
Mit dieser integrierten Funktion müssen wir uns nie Gedanken über Kollisionen von CSS-Klassennamen, Spezifitätskriege oder verschwendete Zeit bei der Suche nach eindeutigen Klassennamen im gesamten Codebase machen.
Diese Funktion ist für die komponentenbasierte Entwicklung von unschätzbarem Wert.
SSR (Server-Side Rendering)
Wenn wir Single Page Apps (SPAs) betrachten – bei denen der HTTP-Server nur eine anfängliche leere HTML-Seite liefert und die gesamte Darstellung im Browser erfolgt –, ist Server-Side Rendering (SSR) möglicherweise nicht sehr nützlich. Jede Website oder Anwendung, die von Suchmaschinen analysiert und indiziert werden muss, benötigt jedoch SSR-Seiten, und auch die Stile müssen auf dem Server generiert werden.
Das gleiche Prinzip gilt für Static Site Generators (SSG), bei denen Seiten zusammen mit jedem CSS-Code zur Build-Zeit als statische HTML-Dateien vorab generiert werden.
Die gute Nachricht ist, dass alle von uns getesteten Bibliotheken SSR unterstützen und sie damit für praktisch jeden Projekttyp in Frage kommen.
Automatische Vendor-Präfixe
Aufgrund des komplexen CSS-Standardisierungsprozesses kann es Jahre dauern, bis eine neue CSS-Funktion in allen gängigen Browsern verfügbar ist. Ein Ansatz zur Bereitstellung eines frühen Zugangs zu experimentellen Funktionen ist die Bereitstellung nicht standardmäßiger CSS-Syntax unter einem Vendor-Präfix
/* WebKit browsers: Chrome, Safari, most iOS browsers, etc */
-webkit-transition: all 1s ease;
/* Firefox */
-moz-transition: all 1s ease;
/* Internet Explorer and Microsoft Edge */
-ms-transition: all 1s ease;
/* old pre-WebKit versions of Opera */
-o-transition: all 1s ease;
/* standard */
transition: all 1s ease;
Es stellt sich jedoch heraus, dass Vendor-Präfixe problematisch sind und die CSS Working Group beabsichtigt, sie in Zukunft nicht mehr zu verwenden. Wenn wir ältere Browser, die die Standard-Spezifikation nicht implementieren, vollständig unterstützen wollen, müssen wir wissen, welche Funktionen ein Vendor-Präfix erfordern.
Glücklicherweise gibt es Tools, die es uns ermöglichen, die Standard-Syntax in unserem Quellcode zu verwenden und die erforderlichen Vendor-Präfix-CSS-Eigenschaften automatisch zu generieren. Alle CSS-in-JS-Bibliotheken bieten diese Funktion ebenfalls standardmäßig an.
Keine Inline-Stile
Es gibt einige CSS-in-JS-Bibliotheken, wie Radium oder Glamor, die alle Stildefinitionen als Inline-Stile ausgeben. Diese Technik hat eine erhebliche Einschränkung, da es unmöglich ist, Pseudo-Klassen, Pseudo-Elemente oder Media Queries mit Inline-Stilen zu definieren. Daher mussten diese Bibliotheken diese Funktionen durch Hinzufügen von DOM-Event-Listenern hacken und Stilaktualisierungen von JavaScript aus auslösen, im Wesentlichen native CSS-Funktionen wie :hover, :focus und viele mehr neu erfinden.
Es ist auch allgemein anerkannt, dass Inline-Stile weniger performant sind als Klassennamen. Es ist üblicherweise eine abgeratene Praxis, sie als primären Ansatz für das Styling von Komponenten zu verwenden.
Alle aktuellen CSS-in-JS-Bibliotheken haben sich von der Verwendung von Inline-Stilen abgewandt und CSS-Klassennamen übernommen, um Stildefinitionen anzuwenden.
Volle CSS-Unterstützung
Eine Folge der Verwendung von CSS-Klassen anstelle von Inline-Stilen ist, dass es keine Einschränkungen gibt, welche CSS-Eigenschaften wir verwenden können und welche nicht. Während unserer Analyse waren wir besonders interessiert an
- Pseudo-Klassen und -Elementen;
- Media Queries;
- Keyframe-Animationen.
Alle von uns analysierten Bibliotheken bieten volle Unterstützung für alle CSS-Eigenschaften.
Unterscheidende Merkmale
Hier wird es noch interessanter. Fast jede Bibliothek bietet eine einzigartige Reihe von Funktionen, die unsere Entscheidung bei der Auswahl der geeigneten Lösung für ein bestimmtes Projekt stark beeinflussen können. Einige Bibliotheken haben eine bestimmte Funktion eingeführt, während andere bestimmte Funktionen übernommen oder sogar verbessert haben.
React-spezifisch oder Framework-agnostisch?
Es ist kein Geheimnis, dass CSS-in-JS im React-Ökosystem weiter verbreitet ist. Deshalb sind einige Bibliotheken speziell für React entwickelt worden: Styled JSX, styled-components und Stitches.
Es gibt jedoch viele Bibliotheken, die Framework-agnostisch sind und daher für jedes Projekt verwendet werden können: Emotion, Treat, TypeStyle, Fela, JSS oder Goober.
Wenn wir Vanilla-JavaScript-Code oder andere Frameworks als React unterstützen müssen, ist die Entscheidung einfach: Wir sollten eine Framework-agnostische Bibliothek wählen. Wenn wir uns jedoch mit einer React-Anwendung befassen, haben wir eine viel größere Auswahl, was die Entscheidung letztendlich schwieriger macht. Lassen Sie uns also andere Kriterien untersuchen.
Co-Location von Stilen/Komponenten
Die Möglichkeit, Stile zusammen mit ihren Komponenten zu definieren, ist eine sehr praktische Funktion, die die Notwendigkeit beseitigt, zwischen zwei verschiedenen Dateien hin und her zu wechseln: der .css- oder .less/.scss-Datei, die die Stile enthält, und der Komponentendatei, die das Markup und Verhalten enthält.
React Native StyleSheets, Vue.js SFCs oder Angular Components unterstützen die Co-Location von Stilen standardmäßig, was sich sowohl in der Entwicklung als auch in der Wartung als echter Vorteil erweist. Wir haben immer die Möglichkeit, die Stile in eine separate Datei zu extrahieren, falls wir der Meinung sind, dass sie den Rest des Codes verdecken.

Fast alle CSS-in-JS-Bibliotheken unterstützen die Co-Location von Stilen. Die einzige Ausnahme, auf die wir gestoßen sind, war Treat, die verlangt, dass wir die Stile in einer separaten .treat.ts-Datei definieren, ähnlich wie bei CSS Modules.
Syntax der Stildefinition
Es gibt zwei verschiedene Methoden, mit denen wir unsere Stile definieren können. Einige Bibliotheken unterstützen nur eine Methode, während andere recht flexibel sind und beide unterstützen.
Tagged Templates-Syntax
Die Tagged Templates-Syntax erlaubt es uns, Stile als eine Zeichenkette aus einfachem CSS-Code innerhalb eines Standard- ES-Template-Literal zu definieren
// consider "css" being the API of a generic CSS-in-JS library
const heading = css`
font-size: 2em;
color: ${myTheme.color};
`;
Wir sehen, dass
- CSS-Eigenschaften in Kebab-Case geschrieben sind, genau wie reguläres CSS;
- JavaScript-Werte interpoliert werden können;
- wir bestehenden CSS-Code einfach migrieren können, ohne ihn neu schreiben zu müssen.
Einige Dinge, die man beachten sollte
- Um Syntaxhervorhebung und Code-Vervollständigung zu erhalten, ist ein zusätzliches Editor-Plugin erforderlich; dieses Plugin ist jedoch normalerweise für gängige Editoren wie VSCode, WebStorm und andere verfügbar.
- Da der endgültige Code letztendlich in JavaScript ausgeführt werden muss, müssen die Stildefinitionen analysiert und in JavaScript-Code konvertiert werden. Dies kann entweder zur Laufzeit oder zur Build-Zeit erfolgen und verursacht einen geringen Overhead bei der Bundle-Größe oder der Berechnung.
Object Styles-Syntax
Die Object Styles-Syntax erlaubt es uns, Stile als reguläre JavaScript-Objekte zu definieren
// consider "css" being the API of a generic CSS-in-JS library
const heading = css({
fontSize: "2em",
color: myTheme.color,
});
Wir sehen, dass
- CSS-Eigenschaften sind in CamelCase geschrieben und Zeichenfolgenwerte müssen in Anführungszeichen gesetzt werden;
- JavaScript-Werte können wie erwartet referenziert werden;
- es fühlt sich nicht wie das Schreiben von CSS an, da wir stattdessen Stile mit einer leicht unterschiedlichen Syntax definieren, aber mit den gleichen Eigenschaftsnamen und -werten wie in CSS (lassen Sie sich davon nicht einschüchtern, Sie werden sich schnell daran gewöhnen);
- die Migration bestehender CSS würde eine Umschreibung in dieser neuen Syntax erfordern.
Einige Dinge, die man beachten sollte
- Syntaxhervorhebung ist standardmäßig verfügbar, da wir tatsächlich JavaScript-Code schreiben.
- Um Code-Vervollständigung zu erhalten, muss die Bibliothek CSS-Typdefinitionen bereitstellen, von denen die meisten das beliebte CSSType-Paket erweitern.
- Da die Stile bereits in JavaScript geschrieben sind, ist keine zusätzliche Parsing- oder Konvertierung erforderlich.
| Bibliothek | Tagged template | Object styles |
|---|---|---|
| styled-components | ✅ | ✅ |
| Emotion | ✅ | ✅ |
| Goober | ✅ | ✅ |
| Compiled | ✅ | ✅ |
| Fela | 🟠 | ✅ |
| JSS | 🟠 | ✅ |
| Treat | ❌ | ✅ |
| TypeStyle | ❌ | ✅ |
| Stitches | ❌ | ✅ |
| Styled JSX | ✅ | ❌ |
✅ Volle Unterstützung 🟠 Benötigt Plugin ❌ Nicht unterstützt
Methode zum Anwenden von Stilen
Nachdem wir nun wissen, welche Optionen für die Stildefinition verfügbar sind, schauen wir uns an, wie sie auf unsere Komponenten und Elemente angewendet werden.
Verwendung eines Klassenattributs / className-Props
Der einfachste und intuitivste Weg, die Stile anzuwenden, ist, sie einfach als Klassennamen anzuhängen. Bibliotheken, die diesen Ansatz unterstützen, bieten eine API, die eine Zeichenkette zurückgibt, die die generierten eindeutigen Klassennamen ausgibt
// consider "css" being the API of a generic CSS-in-JS library
const heading_style = css({
color: "blue"
});
Als Nächstes können wir heading_style, das eine Zeichenkette von generierten CSS-Klassennamen enthält, nehmen und sie auf unser HTML-Element anwenden
// Vanilla DOM usage
const heading = `<h1 class="${heading_style}">Title</h1>`;
// React-specific JSX usage
function Heading() {
return <h1 className={heading_style}>Title</h1>;
}
Wie wir sehen, ähnelt diese Methode ziemlich dem traditionellen Styling: Zuerst definieren wir die Stile, dann hängen wir die Stile dort an, wo wir sie brauchen. Die Lernkurve ist niedrig für jeden, der bereits CSS geschrieben hat.
Verwendung einer <Styled />-Komponente
Eine weitere beliebte Methode, die zuerst von der styled-components-Bibliothek eingeführt wurde (und nach ihr benannt ist), verfolgt einen anderen Ansatz.
// consider "styled" being the API for a generic CSS-in-JS library
const Heading = styled("h1")({
color: "blue"
});
Anstatt die Stile separat zu definieren und sie an bestehende Komponenten oder HTML-Elemente anzuhängen, verwenden wir eine spezielle API, indem wir angeben, welche Art von Element wir erstellen möchten und welche Stile wir daran anhängen möchten.
Die API gibt eine neue Komponente zurück, mit bereits angewendeten Klassennamen, die wir wie jede andere Komponente in unserer Anwendung rendern können. Dies beseitigt im Grunde die Zuordnung zwischen der Komponente und ihren Stilen.
Verwendung des css-Props
Eine neuere Methode, die von Emotion populär gemacht wurde, erlaubt es uns, die Stile an ein spezielles Prop zu übergeben, das normalerweise css genannt wird. Diese API ist nur für JSX-basierte Syntax verfügbar.
// React-specific JSX syntax
function Heading() {
return <h1 css={{ color: "blue" }}>Title</h1>;
}
Dieser Ansatz hat einen gewissen ergonomischen Vorteil, da wir keine spezielle API aus der Bibliothek importieren und verwenden müssen. Wir können die Stile einfach an dieses css-Prop übergeben, ähnlich wie wir Inline-Stile verwenden würden.
Beachten Sie, dass dieses benutzerdefinierte css-Prop kein Standard-HTML-Attribut ist und über ein separates Babel-Plugin, das von der Bibliothek bereitgestellt wird, aktiviert und unterstützt werden muss.
| Bibliothek | className | <Styled /> | css Prop |
|---|---|---|---|
| styled-components | ❌ | ✅ | ✅ |
| Emotion | ✅ | ✅ | ✅ |
| Goober | ✅ | ✅ | 🟠 2 |
| Compiled | 🟠 1 | ✅ | ✅ |
| Fela | ✅ | ❌ | ❌ |
| JSS | ✅ | 🟠 2 | ❌ |
| Treat | ✅ | ❌ | ❌ |
| TypeStyle | ✅ | ❌ | ❌ |
| Stitches | ✅ | ✅ | 🟠 1 |
| Styled JSX | ✅ | ❌ | ❌ |
✅ Volle Unterstützung 🟠 1 Begrenzte Unterstützung 🟠 2 Benötigt Plugin ❌ Nicht unterstützt
Stil-Ausgabe
Es gibt zwei sich gegenseitig ausschließende Methoden, um Stile zu generieren und an den Browser zu liefern. Beide Methoden haben Vor- und Nachteile, analysieren wir sie also im Detail.
<style>-injektierte DOM-Stile
Die meisten CSS-in-JS-Bibliotheken injizieren Stile zur Laufzeit in das DOM, entweder über einen oder mehrere <style>-Tags oder über die CSSStyleSheet-API, um Stile direkt im CSSOM zu verwalten. Während SSR werden Stile immer als <style>-Tag im <head> der gerenderten HTML-Seite angehängt.
Es gibt einige wichtige Vorteile und bevorzugte Anwendungsfälle für diesen Ansatz
- Das Inlining der Stile während SSR bietet eine Steigerung der Seitenladeleistungsmetriken wie FCP (First Contentful Paint), da das Rendering nicht durch das Abrufen einer separaten
.css-Datei vom Server blockiert wird. - Es bietet standardmäßig Critical CSS Extraction während SSR, indem nur die für das Rendern der anfänglichen HTML-Seite erforderlichen Stile inline gesetzt werden. Außerdem werden alle dynamischen Stile entfernt, was die Ladezeit weiter verbessert, da weniger Code heruntergeladen wird.
- Dynamisches Styling ist in der Regel einfacher zu implementieren, da dieser Ansatz besser für hochgradig interaktive Benutzeroberflächen und Single-Page Applications (SPA) geeignet zu sein scheint, bei denen die meisten Komponenten clientseitig gerendert werden.
Die Nachteile sind im Allgemeinen mit der Gesamtgröße des Bundles verbunden
- eine zusätzliche Laufzeitbibliothek wird für die Handhabung des dynamischen Stylings im Browser benötigt;
- die Inline-SSR-Stile werden nicht standardmäßig zwischengespeichert und müssen bei jeder Anfrage an den Browser gesendet werden, da sie Teil der vom Server gerenderten
.html-Datei sind; - die SSR-Stile, die in die
.html-Datei inline gesetzt werden, werden während des Rehydration-Prozesses erneut als JavaScript-Ressourcen an den Browser gesendet.
Statische .css-Dateiexktion
Es gibt eine sehr kleine Anzahl von Bibliotheken, die einen völlig anderen Ansatz verfolgen. Anstatt die Stile in das DOM zu injizieren, generieren sie statische .css-Dateien. Aus Sicht der Ladeleistung erhalten wir die gleichen Vor- und Nachteile wie beim Schreiben von reinem CSS.
- Die Gesamtmenge des ausgelieferten Codes ist viel geringer, da kein zusätzlicher Laufzeitcode oder Rehydration-Overhead erforderlich ist.
- Statische
.css-Dateien profitieren von der Browser-Caching-Funktion, sodass nachfolgende Anfragen an dieselbe Seite die Stile nicht erneut abrufen müssen. - Dieser Ansatz scheint attraktiver zu sein, wenn es um SSR-Seiten oder statisch generierte Seiten geht, da diese von den Standard-Caching-Mechanismen profitieren.
Es gibt jedoch einige wichtige Nachteile, die wir beachten müssen
- Der erste Besuch einer Seite mit leerem Cache wird bei Verwendung dieser Methode im Vergleich zur zuvor erwähnten Methode normalerweise eine längere FCP haben. Die Entscheidung, ob wir für Erstbesucher oder wiederkehrende Besucher optimieren wollen, könnte bei der Wahl dieses Ansatzes eine entscheidende Rolle spielen.
- Alle dynamischen Stile, die auf der Seite verwendet werden können, werden in das vorab generierte Bundle aufgenommen, was potenziell zu größeren
.css-Ressourcen führt, die vorab geladen werden müssen.
Fast alle von uns getesteten Bibliotheken implementieren die erste Methode, bei der die Stile in das DOM injiziert werden. Die einzige getestete Bibliothek, die statische .css-Dateien extrahiert, ist Treat. Es gibt andere Bibliotheken, die diese Funktion unterstützen, wie Astroturf, Linaria und style9, die nicht in unsere endgültige Analyse aufgenommen wurden.
Atomic CSS
Einige Bibliotheken gingen bei der Optimierung noch einen Schritt weiter und implementierten eine Technik namens Atomic CSS-in-JS, inspiriert von Frameworks wie Tachyons oder Tailwind.
Anstatt CSS-Klassen zu generieren, die alle für ein bestimmtes Element definierten Eigenschaften enthalten, generieren sie für jede eindeutige CSS-Eigenschaft/-Wert-Kombination eine eindeutige CSS-Klasse.
/* classic, non-atomic CSS class */
._wqdGktJ {
color: blue;
display: block;
padding: 1em 2em;
}
/* atomic CSS classes */
._ktJqdG { color: blue; }
._garIHZ { display: block; }
/* short-hand properties are usually expanded */
._kZbibd { padding-right: 2em; }
._jcgYzk { padding-left: 2em; }
._ekAjen { padding-bottom: 1em; }
._ibmHGN { padding-top: 1em; }
Dies ermöglicht ein hohes Maß an Wiederverwendbarkeit, da jede dieser einzelnen CSS-Klassen überall in der Codebasis wiederverwendet werden kann.
Theoretisch funktioniert dies in großen Anwendungen wirklich gut. Warum? Weil es eine endliche Anzahl von eindeutigen CSS-Eigenschaften gibt, die für eine gesamte Anwendung benötigt werden. Der Skalierungsfaktor ist daher nicht linear, sondern logarithmisch, was zu weniger CSS-Ausgabe im Vergleich zu nicht-atomarem CSS führt.

Aber es gibt einen Haken: individuelle Klassennamen müssen jedem Element zugewiesen werden, das sie benötigt, was zu etwas größeren HTML-Dateien führt.
<!-- with classic, non-atomic CSS classes -->
<h1 class="_wqdGktJ">...</h1>
<!-- with atomic CSS classes -->
<h1 class="_ktJqdG _garIHZ _kZbibd _jcgYzk _ekAjen _ibmHGN">...</h1>
Wir verlagern den Code also im Grunde von CSS nach HTML. Die resultierende Größenänderung hängt von zu vielen Aspekten ab, als dass wir eine definitive Schlussfolgerung ziehen könnten, aber generell sollte die Gesamtmenge der an den Browser gelieferten Bytes reduziert werden.
Fazit
CSS-in-JS wird die Art und Weise, wie wir CSS erstellen, dramatisch verändern und viele Vorteile bieten sowie unsere allgemeine Entwicklungserfahrung verbessern.
Die Wahl der zu übernehmenden Bibliothek ist jedoch nicht einfach und alle Entscheidungen gehen mit vielen technischen Kompromissen einher. Um die für unsere Bedürfnisse am besten geeignete Bibliothek zu identifizieren, müssen wir die Projektanforderungen und ihre Anwendungsfälle verstehen.
- Verwenden wir React oder nicht? React-Anwendungen haben eine größere Auswahl, während Nicht-React-Lösungen eine Framework-agnostische Bibliothek verwenden müssen.
- Beschäftigen wir uns mit einer hochgradig interaktiven Anwendung mit clientseitiger Rendern? In diesem Fall sind wir wahrscheinlich nicht sehr besorgt über den Overhead der Rehydrierung oder kümmern uns viel um die Extraktion statischer
.css-Dateien. - Bauen wir eine dynamische Website mit SSR-Seiten? Dann ist die Extraktion statischer
.css-Dateien wahrscheinlich eine bessere Option, da sie uns die Vorteile des Cachings ermöglicht. - Müssen wir vorhandenen CSS-Code migrieren? Die Verwendung einer Bibliothek, die Tagged Templates unterstützt, erleichtert und beschleunigt die Migration.
- Wollen wir für Erstbesucher oder wiederkehrende Besucher optimieren? Statische
.css-Dateien bieten die beste Erfahrung für wiederkehrende Besucher, indem sie die Ressourcen cachen, aber der erste Besuch erfordert eine zusätzliche HTTP-Anfrage, die das Rendern der Seite blockiert. - Aktualisieren wir unsere Stile häufig? Alle gecachten
.css-Dateien sind wertlos, wenn wir unsere Stile häufig aktualisieren und damit jeden Cache ungültig machen. - Wiederverwenden wir viele Stile und Komponenten? Atomares CSS glänzt, wenn wir viele CSS-Eigenschaften in unserer Codebasis wiederverwenden.
Die Beantwortung der oben genannten Fragen hilft uns zu entscheiden, nach welchen Funktionen wir bei der Auswahl einer CSS-in-JS-Lösung suchen müssen, und ermöglicht es uns, fundiertere Entscheidungen zu treffen.
Haben Sie jayesstee ausprobiert?
Nein, ich habe noch nichts davon gehört. Soweit ich aus der Dokumentation ersehen kann, ist es hauptsächlich eine Template-Engine, daher liegt es weit außerhalb des Rahmens meiner Analyse, die sich auf CSS-in-JS mit TypeScript und Next.js konzentriert.
Oder… Sie können SCSS mit BEM verwenden. Ich habe es viele Male versucht und finde immer noch, dass Pseudo-CSS in einer JS-Komponentendatei nur Verschmutzung und Unsinn ist.
Ich mag es nicht, durch schlechtes Styling scrollen zu müssen, um meinen echten JavaScript-Code zu sehen.
Alle diese Funktionen können mit SASS oder Less erzielt werden. Css-in-js ist ein überentwickeltes Monster.
Dieser Artikel debattiert nicht, "ob" oder "warum" Sie CSS-in-JS verwenden sollten. Er richtet sich an Personen, die diesen Ansatz verwenden möchten, aber Schwierigkeiten haben, herauszufinden, welche Lösung sie wählen sollen.
Wenn SCSS mit BEM all Ihren Bedürfnissen entspricht, brauchen Sie natürlich nichts weiter.
Ich verwende BEM seit 2012 und SCSS seit 2009. Beide sind großartig und funktionieren gut für relativ kleine Projekte und kleine Teams. Das Fehlen von Typsicherheit, Refactoring-Tools oder jeglicher Möglichkeit, Konventionen außer durch Code-Reviews zu erzwingen/zu überprüfen, macht sie einfach umständlich zu skalieren und zu warten. Ganz zu schweigen vom Teilen von typsicheren Design-Tokens (Variablen) zwischen (S)CSS und TypeScript.
Sie können das CSS immer in eine andere Datei verschieben, um die Lesbarkeit zu verbessern. Sie können auch CSS-Module mit SCSS für die Eingrenzung verwenden, obwohl Sie dann nicht die Eliminierung von totem Code erhalten, die CSS-in-JS bietet. JS bietet auch die Möglichkeit der Typsicherheit (nicht die Eric Bailey-Variante).
Nachdem ich an großen Codebasen mit beiden Ansätzen gearbeitet habe, ist BEM nicht mehr das richtige Werkzeug. Sie können SCSS immer noch mit CSS-Modulen verwenden, aber die manuelle CSS-Eingrenzung ist fehleranfälliger, unabhängig von der Fähigkeit des Entwicklers. Es ist eine finanzielle Belastung.
BEM skaliert nicht. Es erhöht nur die CSS-Nutzlast – das lineare Skalierungsproblem, das im Artikel hervorgehoben wird. Es funktioniert auch nicht gut in großen Teams, da die Namensregeln zu komplex sind und kein Teammitglied sie alle richtig im Gedächtnis behalten und anwenden kann. Zeit, die für das Aufdecken von Inkonsistenzen in Code-Reviews aufgewendet wird, ist verlorene Zeit.
Ich weiß, dass es buchstäblich 50 davon gibt, was einer der Gründe ist, warum ich dies nicht weiterverfolgt habe – aber dies war mein Versuch vor einigen Jahren
https://gist.github.com/mindplay-dk/47bc597dcbc28bea009b02c5a0c9010e
Es ist eine Objektnotation, aber sie ermöglicht SASS-ähnliche Dinge wie verschachtelte Selektoren, Fortsetzungen (der &-Operator) und Media-Queries und so weiter. Ich war überrascht, wie wenig Code das braucht – ich glaube, das waren weniger als 0,5 K minifiziert. Ich konnte die Typprüfung für verschachtelte Regeln nie richtig zum Laufen bringen, ich denke, das wäre jetzt möglich. Aber natürlich ist die eigentliche Arbeit die Vorabkompilierung und all das – ich denke, ich habe aufgegeben, nachdem ich den spaßigen Teil gemacht hatte.
Gibt es eine fertige Bibliothek mit SASS-ähnlichen Funktionen und verschachtelter Objektnotation?
Die meisten von uns getesteten Bibliotheken unterstützen
– beliebige verschachtelte Selektoren (außer Treat)
– kontextuelle Stile, wie z. B. „&“ (außer Styled JSX)
– Media-Queries, Keyframe-Animationen
– Objektstil-Syntax (außer Styled JSX und Linaria)
Sie können sich hier die Übersicht ansehen
https://github.com/andreipfeiffer/css-in-js/#overview
Vielen Dank für die Erklärung der verschiedenen Möglichkeiten, Stile in CSS-in-JS zu erstellen und zu konsumieren. Ich bin neu in diesem CSS-in-JS-Konzept, immer wenn ich Code sehe, der CSSinjs verwendet, bin ich verwirrt über all die Wege, wie sie CSSinjs verwenden. Jetzt, nachdem ich Ihren Artikel gelesen habe, habe ich Klarheit gewonnen.
Hier könnten Sie ReachUI hinzufügen, das in der Community mehrmals erwähnt wird.
Als Entwickler mit SCSS-Erfahrung benötigen wir eine bessere Code-Vervollständigung/Intellisense und müssen alle SCSS-Snippets und Emmet-Tricks migrieren, wenn wir zu CSSinjs migrieren.
Ich freue mich, dass Sie dies nützlich fanden :)
ReachUI und Material UI sind Designsysteme, die auch ihre eigenen Komponentenbibliotheken haben. Tatsächlich bieten sie auch eine Möglichkeit zur Anpassung der Stile, wobei eine Art CSS-in-JS-Ansatz verwendet wird.
Meine Forschung konzentriert sich auf Lösungen, die außerhalb des Kontexts eines bestimmten Designsystems angewendet werden können. Die hier vorgestellten allgemeinen Funktionen gelten jedoch auch für die Implementierungen von CSS-in-JS in diesen Designsystemen.
Schöner Artikel, eine weitere Sache, die es wert sein könnte, erwähnt zu werden, ist die Möglichkeit, dynamische Themen wie die ThemeProvider von Emotion zu verwenden. Für mich ist dies einer der weiteren großen Vorteile, nämlich die Möglichkeit der benutzerdefinierten White-Labeling.
Jede Lösung implementiert dies anders: Emotion verwendet ein über einen Kontext übergebenes Objekt, und ich glaube, Stitches verwendet CSS-Variablen.
Sie haben Recht, ich habe mich nicht auf die Details des Themas konzentriert, obwohl die meisten hier behandelten Bibliotheken (mit wenigen Ausnahmen) eine Möglichkeit dazu bieten.
Das könnte definitiv etwas sein, das es wert ist, erforscht zu werden.
„Da es eine endliche Anzahl von eindeutigen CSS-Eigenschaften gibt, die für eine gesamte Anwendung benötigt werden. Der Skalierungsfaktor ist daher nicht linear, sondern logarithmisch, was zu weniger CSS-Ausgabe im Vergleich zu nicht-atomarem CSS führt.“
Der Skalierungsfaktor ist, wie Sie es ausdrücken, auf die Anzahl der eindeutigen CSS-Eigenschaften fixiert, also konstant und nicht logarithmisch.
Die Anzahl der eindeutigen CSS-Eigenschaften ist „zu einem bestimmten Zeitpunkt“ konstant. Wenn Ihre Anwendung wächst, wächst normalerweise auch CSS. Eine bestimmte Menge an CSS-Eigenschaften wird jedoch wiederverwendet, da sie zuvor verwendet wurden, sodass nur ein Teil des hinzugefügten CSS neue Eigenschaften enthält (oder genauer gesagt „Eigenschaft/Wert-Paare“).
Daher wird CSS im Laufe der Zeit bis zu einem bestimmten Punkt wachsen, es bleibt nicht konstant. Die einzige Möglichkeit, wie es theoretisch konstant sein könnte, besteht darin, „alle möglichen Eigenschaft/Wert-Paare, die Sie jemals verwenden werden“ zu bündeln, unabhängig davon, ob sie tatsächlich verwendet werden oder nicht. Aber das wäre überhaupt nicht optimal.
Zumindest verstehe ich Atomic CSS so :)
Etwas, das in diesem Artikel auffallend fehlt, ist das Thema der Anpassung von Komponenten mit Stilen. Angenommen, ich erstelle eine „Timeline“-React-Komponente, mit der Benutzer einen Zeitbereich über einen Schieberegler und ein Paar Datumsfelder auswählen können. Sicher, die Timeline benötigt etwas CSS, aber es könnte durchaus ausreichen, Inline-Style={}s anzugeben.
Da es sich um eine generische Komponente handelt, möchte ich das Styling nicht in der Komponente selbst (außer ihrem Standardaussehen) festlegen. Ich möchte, dass die Komponente Stile zulässt, die vom Aufrufer/Elternteil bereitgestellt werden. Welche CSS-Bibliotheken würden mir dabei helfen?
Soweit ich weiß, hängt Ihr Anwendungsfall nicht streng mit CSS-in-JS zusammen, sondern ist eher ein Problem der öffentlichen API einer Komponente. Es hängt wirklich davon ab, wie viel Anpassung Sie den Nutzern Ihrer Komponente anbieten möchten.
Sie können ein Theming-System haben, um eine vollständige Anpassung aller Komponenten zu ermöglichen (nützlich zum Anpassen einer ganzen Bibliothek von Komponenten für Ihre Anwendung).
oder Sie können eine vollständige Anpassung und Stilüberschreibung zulassen (nützlich für einmalige, nicht wiederverwendbare Variationen).
Sie beziehen sich wahrscheinlich auf das 3. Szenario. Das hängt streng von der Methode der „Stilanwendung“ ab.
– Wenn die Bibliothek Klassennamen-Strings verwendet, kann Ihre Komponente eine zusätzliche
className-Prop erhalten, die auf dem Konsumenten definiert ist und dort, wo sie benötigt wird, verkettet wird.– Mit Styled Components können Sie neue Komponenten erstellen, die auf bestehenden Komponenten basieren, aber mit anderen Stilen.
– Mit der CSS-Prop können Sie einfach ein zusätzliches Objekt an die Komponente übergeben, und die Bibliothek kümmert sich um das Zusammenführen der Stile.
Dies ist natürlich etwas, das im Detail erforscht werden kann. Ich werde es als Issue hinzufügen und in naher Zukunft analysieren.
Sie sollten sich Aesthetic ansehen, das ein Designsystem in Verbindung mit einer CSS-in-JS-Lösung anbietet. https://aestheticsuite.dev
Der angegebene Link hilft mir nicht, diese Schlussfolgerung zu verstehen. Schneller in welchem Kontext?
Beim Erstellen des CSSDOM? Ich nehme an, eine Klasse muss eine Nachschlageoperation durchführen, um die Stile zu finden, das sollte langsamer sein, oder?
Hallo Drew,
Der angegebene Link hat oben einen Reiter „Ergebnisse“ (neben dem Reiter „Übersicht“).
Sie können auf „Benchmark ausführen“ klicken, um die Testsuite verschiedener trivialer Implementierungen auszuführen, um die Stile eines Knotens zu aktualisieren.
Sie können die Implementierungen auch in jedem einzelnen Reiter neben „Ergebnisse“ überprüfen.
Hinweis: Es ist nicht meine eigene Implementierung, ich habe keine eigenen Benchmarks durchgeführt. Dies ist ein Beispiel, das ich bei der Suche nach solchen Ressourcen gefunden habe.
Ich habe nie die Anziehungskraft der Art und Weise verstanden, wie Styled-Components CSS deklariert. Warum sollte man eine Klasse instanziieren müssen, wenn man Stile deklariert? Verringert das nicht die Wiederverwendbarkeit? Wenn ich eine Gruppe von Deklarationen habe, die einen bestimmten typografischen Stil definieren, möchte ich sie vielleicht in einem Absatz, einer Bildunterschrift, einer Tabellenzelle oder anderswo verwenden. Warum sollte ich sie an ein bestimmtes Element binden wollen?
Ich weiß, was Sie meinen, ich fühle dasselbe, weil ich den Standardansatz so viele Jahre lang verwendet habe
1. Definieren Sie die Stile in einer CSS-Klasse
2. Wenden Sie die Klasse auf HTML-Elemente an
Mit der Syntax von Styled Components ist die HTML-Elementdefinition und die Stildefinition ein einziger Schritt.
Wenn Sie über Kapselung nachdenken, also dass „jede Komponente ihre eigenen Stile kapseln sollte“, dann macht diese Syntax wirklich Sinn.
Wenn Sie bestimmte Stile wiederverwenden möchten, können Sie sie immer komponieren oder interpolieren, wenn Sie die Template-String-Syntax verwenden.
Oder Sie können eine Basiskomponente erstellen und diese dann erweitern, um spezifische Komponenten zu definieren. Natürlich könnten Sie argumentieren: „Warum sollte ich eine Basiskomponente erstellen, wenn ich sie nicht explizit benötige?“. Nun, der Schaden, den sie anrichtet, ist wirklich vernachlässigbar. Und betrachten Sie auch alle anderen Vorteile, bevor Sie sich auf einen einzigen Nachteil konzentrieren.
Nur um klarzustellen, ich verteidige sie nicht. Ich benutze diese Syntax auch nicht, da sie mir persönlich nicht passt. Ich versuche nur, die Kompromisse objektiv zu verstehen. Und wenn ich an einem Projekt arbeiten würde, das bereits SC verwendet, würde ich viele Vorteile in diesem Ansatz finden.
Ihre Wiederverwendungseinheit ist keine Klasse, sondern eine Komponente. Sie würden sie auf die gleiche Weise wiederverwenden. Stellen Sie es sich so vor, als würden Sie etwas mit einem benutzerdefinierten HTML-Element umschließen, anstatt einem vorhandenen eine Eigenschaft hinzuzufügen.
Diese CSS-Literalzeichenkette muss in JS konvertiert werden, das stimmt nicht, es gibt eine alternative direkte Injektionsmethode mit document.adoptedStyleSheets
siehe https://github.com/WebSVG/voronoi/blob/cd1398db026b65f4cab40619c7740b0188627db9/src/scale-grid.js#L117
Aus den MDN-Dokumenten
Die adoptedStyleSheets […] wird verwendet, um ein Array von konstruierten Stylesheets festzulegen.
Was auch immer Sie an adoptedStyleSheets() übergeben, Sie müssen es mit CSSStyleSheet() instanziieren, das Objekte verwendet.
Aber selbst wenn Sie einen String an die DOM-API übergeben, muss sie ihn trotzdem parsen, validieren, in ein Objekt konvertieren und mit dem vorhandenen CSSOM zusammenführen.