In letzter Zeit gab es viel verdienten Hype um Svelte, wobei das Projekt über 24.000 GitHub-Sterne angesammelt hat. Wohl das einfachste JavaScript-Framework, das es gibt, wurde Svelte von Rich Harris geschrieben, dem Entwickler hinter Rollup. Es gibt vieles, was an Svelte gefällt (Performance, integriertes Zustandsmanagement, das Schreiben von korrektem Markup anstelle von JSX), aber für mich war der Hauptgrund seine Herangehensweise an CSS.
Single-File-Komponenten
React hat keine Meinung dazu, wie Stile definiert werden
—React-Dokumentation
Ein UI-Framework, das keine eingebaute Möglichkeit zum Hinzufügen von Stilen zu seinen Komponenten hat, ist unvollständig.
—Rich Harris, Schöpfer von Svelte
In Svelte können Sie CSS in einer Stylesheet schreiben, wie Sie es normalerweise in einem typischen Projekt tun würden. Sie können auch CSS-in-JS-Lösungen wie styled-components und Emotion verwenden, wenn Sie möchten. Es ist immer üblicher geworden, Code nach Komponenten zu unterteilen, anstatt nach Dateityp. React erlaubt beispielsweise die Zusammenfassung des Markups und JavaScripts einer Komponente. In Svelte wird dies einen logischen Schritt weiter gedacht: Das JavaScript, das Markup und das Styling für eine Komponente können alle zusammen in einer einzigen `.svelte`-Datei existieren. Wenn Sie jemals Single-File-Komponenten in Vue verwendet haben, wird Svelte Ihnen vertraut vorkommen.
// button.svelte
<style>
button {
border-radius: 0;
background-color: aqua;
}
</style>
<button>
<slot/>
</button>
Stile sind standardmäßig gekapselt
Standardmäßig sind die in einer Svelte-Datei definierten Stile *gekapselt*. Ähnlich wie bei CSS-in-JS-Bibliotheken oder CSS Modules generiert Svelte beim Kompilieren eindeutige Klassennamen, um sicherzustellen, dass die Stile eines Elements niemals mit Stilen eines anderen Elements in Konflikt geraten.
Das bedeutet, Sie können einfache Elementselektoren wie div und button in einer Svelte-Komponentendatei verwenden, ohne sich mit Klassennamen auseinandersetzen zu müssen. Wenn wir auf die Button-Stile in unserem früheren Beispiel zurückkommen, wissen wir, dass ein Regelwerk für <button> nur auf unsere <Button>-Komponente angewendet wird – nicht auf andere HTML-Button-Elemente auf der Seite. Wenn Sie mehrere Buttons innerhalb einer Komponente haben und diese unterschiedlich gestalten möchten, benötigen Sie immer noch Klassen. Klassen werden ebenfalls von Svelte gekapselt.
Die von Svelte generierten Klassen sehen wie Kauderwelsch aus, da sie auf einem Hash der Komponentenstile basieren (z. B. svelte-433xyz). Dies ist viel einfacher als eine Namenskonvention wie BEM. Zugegebenermaßen ist die Erfahrung beim Betrachten von Stilen in DevTools etwas schlechter, da die Klassennamen keine Bedeutung haben.

Es ist keine Entweder-Oder-Situation. Sie können Sveltes gekapselte Stile zusammen mit einer regulären Stylesheet verwenden. Ich persönlich schreibe komponentenspezifische Stile innerhalb von .svelte-Dateien, nutze aber Utility-Klassen, die in einer Stylesheet definiert sind. Für globale Stile, die in einer gesamten App verfügbar sein sollen – CSS-Custom-Properties, wiederverwendbare CSS-Animationen, Utility-Klassen, beliebige „Reset“-Stile oder ein CSS-Framework wie Bootstrap – empfehle ich, sie in einer Stylesheet abzulegen, die im Head Ihres HTML-Dokuments verlinkt ist.
Es ermöglicht uns, globale Stile zu erstellen
Wie wir gerade gesehen haben, können Sie eine reguläre Stylesheet verwenden, um globale Stile zu definieren. Sollten Sie globale Stile innerhalb einer Svelte-Komponente definieren müssen, können Sie das auch tun, indem Sie :global verwenden. Dies ist im Wesentlichen eine Möglichkeit, die Kapselung zu umgehen, wann und wo Sie es benötigen.
Zum Beispiel möchte eine Modal-Komponente möglicherweise eine Klasse umschalten, um das Body-Element zu stylen
<style>
:global(.noscroll) {
overflow: hidden;
}
</style>
Nicht verwendete Stile werden markiert
Ein weiterer Vorteil von Svelte ist, dass es Sie während der Kompilierung über nicht verwendete Stile informiert. Mit anderen Worten, es sucht nach Stellen, an denen Stile definiert, aber nie im Markup verwendet werden.
Bedingte Klassen sind prägnant und mühelos
Wenn der Name der JavaScript-Variablen und der Klassenname gleich sind, ist die Syntax unglaublich prägnant. In diesem Beispiel erstelle ich Modifier-Props für einen Full-Width-Button und einen Ghost-Button.
<script>
export let big = false;
export let ghost = false;
</script>
<style>
.big {
font-size: 20px;
display: block;
width: 100%;
}
.ghost {
background-color: transparent;
border: solid currentColor 2px;
}
</style>
<button class:big class:ghost>
<slot/>
</button>
Eine Klasse ghost wird auf das Element angewendet, wenn eine ghost-Prop verwendet wird, und eine Klasse big wird angewendet, wenn eine big-Prop verwendet wird.
<script>
import Button from './Button.svelte';
</script>
<Button big ghost>Click Me</Button>
Svelte verlangt nicht, dass Klassen- und Prop-Namen identisch sind.
<script>
export let primary = false;
export let secondary = false;
</script>
<button
class:c-btn--primary={primary}
class:c-btn--secondary={secondary}
class="c-btn">
<slot></slot>
</button>
Die obige Button-Komponente hat immer eine Klasse c-btn, enthält aber nur dann Modifikator-Klassen, wenn die entsprechende Prop übergeben wird, wie hier
<Button primary>Click Me</Button>
Dies generiert folgendes Markup
<button class="c-btn c-btn--primary">Click Me</button>
Eine beliebige Anzahl von beliebigen Klassen kann mit einer einzigen Prop an eine Komponente übergeben werden
<script>
let class_name = '';
export { class_name as class };
</script>
<button class="c-btn {class_name}">
<slot />
</button>
Dann können Klassen ähnlich wie bei HTML-Markup verwendet werden
<Button class="mt40">Click Me</Button>
Von BEM zu Svelte
Sehen wir uns an, wie viel einfacher Svelte das Schreiben von Stilen im Vergleich zu einer Standard-CSS-Namenskonvention macht. Hier ist eine einfache Komponente, die mit BEM codiert wurde.
.c-card {
border-radius: 3px;
border: solid 2px;
}
.c-card__title {
text-transform: uppercase;
}
.c-card__text {
color: gray;
}
.c-card--featured {
border-color: gold;
}
Mit BEM werden Klassen lang und hässlich. In Svelte sind die Dinge viel einfacher.
<style>
div {
border-radius: 3px;
border: solid 2px;
}
h2 {
text-transform: uppercase;
}
p {
color: gray;
}
.featured {
border-color: gold;
}
</style>
<div class:featured>
<h2>{title}</h2>
<p>
<slot />
</p>
</div>
Es spielt gut mit Präprozessoren zusammen
CSS-Präprozessoren fühlen sich bei der Arbeit mit Svelte viel weniger notwendig an, aber sie können perfekt nebeneinander funktionieren, indem sie ein Paket namens Svelte Preprocess verwenden. Unterstützung ist für Less, Stylus und PostCSS verfügbar, aber hier sehen wir uns Sass an. Das Erste, was wir tun müssen, ist, einige Abhängigkeiten zu installieren
npm install -D svelte-preprocess node-sass
Dann müssen wir autoPreprocess am Anfang der Datei in rollup.config.js importieren.
import autoPreprocess from 'svelte-preprocess';
Als Nächstes suchen wir das Array plugins und fügen preprocess: autoPreprocess() zu Svelte hinzu
export default {
plugins: [
svelte({
preprocess: autoPreprocess(),
...other stuff
Dann müssen wir nur noch angeben, dass wir Sass verwenden, wenn wir in einer Komponentendatei arbeiten, indem wir type="text/scss" oder lang="scss" zum Style-Tag hinzufügen.
<style type="text/scss">
$pink: rgb(200, 0, 220);
p {
color: black;
span {
color: $pink;
}
}
</style>
Dynamische Werte ohne Laufzeit
Wir haben gesehen, dass Svelte die meisten Vorteile von CSS-in-JS Out-of-the-Box mitbringt – aber ohne externe Abhängigkeiten! Allerdings gibt es eine Sache, die Drittanbieterbibliotheken können und Svelte einfach nicht: JavaScript-Variablen in CSS verwenden.
Der folgende Code ist ungültig und funktioniert nicht:
<script>
export let cols = 4;
</script>
<style>
ul {
display: grid;
width: 100%;
grid-column-gap: 16px;
grid-row-gap: 16px;
grid-template-columns: repeat({cols}, 1fr);
}
</style>
<ul>
<slot />
</ul>
Wir können jedoch ähnliche Funktionalität durch die Verwendung von CSS-Variablen erreichen.
<script>
export let cols = 4;
</script>
<style>
ul {
display: grid;
width: 100%;
grid-column-gap: 16px;
grid-row-gap: 16px;
grid-template-columns: repeat(var(--columns), 1fr);
}
</style>
<ul style="--columns:{cols}">
<slot />
</ul>
Ich habe im Laufe der Jahre CSS auf verschiedenste Arten geschrieben: Sass, Shadow DOM, CSS-in-JS, BEM, Atomic CSS und PostCSS. Svelte bietet die intuitivste, zugänglichste und benutzerfreundlichste Styling-API. Wenn Sie mehr über dieses Thema lesen möchten, dann schauen Sie sich das treffend betitelte The Zen of Just Writing CSS von Rich Harris an.
Ich freue mich, einen Svelte-Artikel auf CSS Tricks zu sehen! Ihre Erklärung von BEM zu Svelte sagt alles. Warum haben wir all die Jahre BEM geschrieben, wenn ein Compiler das für uns tun könnte?
Obwohl wir vielleicht keine Codes schreiben sollten, bei denen wir Basiselemente direkt stylen. Selbst in gekapseltem Code kann dies leicht zu Problemen beim Erweitern des Codes führen. Eine bessere Idee meiner Meinung nach ist die Verwendung einfacher Klassennamen wie in Bootstrap. In Svelte haben Sie nicht die CSS-Konflikte, die Bootstrap aufgrund seines Mangels an Namespaces hat.
Ich spiele mit Svelte CSS und Kontext-basiertem Theme mit CSS-Properties (CSS Vars). Dies ist unglaublich leistungsfähig. Sollte viel performanter sein als die üblicherweise mit Styled Components und Emotion verwendete Methode. Insbesondere mit dem neuen CSS.registerProperty(), das CSS-Variablen nicht erben lässt, wodurch sie performanter werden, da sie nur ein Element beeinflussen.
https://codesandbox.io/s/svelte-theme-components-crt54?fontsize=14&module=%2FButton.svelte
Schöner Beitrag! Haben Sie externe Sass-Dateien verwendet? Ich habe Schwierigkeiten, eine einzelne globale.scss-Datei zu importieren, obwohl das Preprocessing von Sass in den Style-Tags funktioniert.
Prost!
In
App.svelteDas ist es, was ich heute benutze, aber dann kann ich das nette Komponenten-Styling für App nicht verwenden :P Es ist nicht so schlimm, aber es wäre schön mit einer besseren Lösung.
Man kann also den Stil nicht vom Komponenten trennen? Denn der erste Teil dieses Artikels impliziert das irgendwie. Ich mag keine Single-File-Komponenten. Ich mag es, mein CSS wiederzuverwenden, und ich mag SASS sehr. Und eine riesige Ansammlung von allem außer der Spüle ist definitiv keine „einen Schritt weiter gehen“. Es sei denn, es ist ein Schritt in den Abgrund.
Man kann Dinge trennen.
Ich glaube nicht, dass „nicht verwendete Stile markiert werden“
Ich denke, sie werden standardmäßig entfernt https://github.com/sveltejs/svelte/issues/697, aber dann bin ich mir nicht sicher, wie man Svelte tatsächlich anweist, bestimmte Stile nicht zu entfernen?
Ich finde es lustig, dass Ihnen das an Svelte gefallen hat, denn das war der Grund, warum ich Svelte endlich aufgegeben habe (und das Debuggen damit war ein Albtraum).
Ja, alles, was Sie erwähnt haben, ist großartig – aber Sie werden feststellen, dass fast alles davon entweder das Styling innerhalb Ihrer Komponente oder zusätzlichen Boilerplate-Code und Redundanz betrifft, um Ihnen das Styling von außerhalb der Komponente zu ermöglichen. Während Sie normalerweise etwas internen CSS benötigen, ist das Styling ausschließlich innerhalb Ihrer Komponente NICHT die Art und Weise, wie die reale Welt funktioniert. Was ist das Erste, was Sie tun, wenn Sie ein neues Webprojekt beginnen? Sie werfen eine reset.css-Datei hinein.
Ich möchte ein Headless UI-Komponentensystem, und das war für mich mit Svelte ein Albtraum. Sie haben es absichtlich sehr schwierig gemacht, Ihre Komponenten auf die übliche, natürliche Weise zu stylen, indem Sie Stile auf das Komponententag selbst anwenden, ohne viel Boilerplate. Zum Beispiel
Die von Ihnen vorgestellte Klassenlösung zum Übergeben einer Klasse in die Komponente war für mich nicht zuverlässig. Svelte begann, von mir übergebene Klassen zufällig zu überschreiben, als es seine Kapselungs-Klasse im Hintergrund zuwies. Ich konnte keine zuverlässige Methode finden, um einer Komponente von außerhalb der Komponente eine Klasse hinzuzufügen, die in einer Produktionsumgebung zuverlässig ist. Eine Klasse zu einem Element hinzufügen zu können, ist unglaublich einschränkend.
Sie können :global verwenden, um Elemente zu stylen, aber es ist wirklich global, was bedeutet, dass es aus Ihrer Datei auf alles auf Ihrer Seite überläuft – nicht nur auf die Elemente und Komponenten in der Datei, an der Sie arbeiten. Daher müssen Sie alles in ein div einwickeln und es überall in Ihrem Code darauf beschränken. Darüber hinaus sieht Ihr Stylesheet bei der Verwendung vieler Komponenten wie eine einzige lange Liste von :globals() aus und ist visuell schwer zu analysieren.
Am schlimmsten ist vielleicht, dass in Svelte das von Ihnen verwendete Komponententag kein echtes Element im Dokument darstellt, ähnlich wie ein template-Tag in HTML. Das ist bei einem template-Tag sinnvoll, da Sie die darin enthaltenen Elemente leicht ansprechen können, aber nicht bei einer gekapselten Komponente, bei der Sie auch die darin enthaltenen Elemente nicht leicht ansprechen können. Die beiden Ideen stehen meiner Meinung nach diametral entgegen.
Dies verursachte alle möglichen Probleme und unnatürliche Wege, die ich einschlagen musste
Ich konnte den Tag-Namen eines Elements in meinem CSS nicht ansprechen – im selben Dokument, in dem sich der Tag befand (ohne ihn in einen weiteren :global-Selektor einzubinden).
Ich konnte nicht etwas tun, wie eine ID an die Komponente anzuhängen und Elemente im Slot der Komponente damit anzusprechen. Ich müsste entweder ein weiteres unnötiges Div um die Komponente wickeln und die eingeschobenen Elemente damit kapseln, oder ich müsste a.) eine benutzerdefinierte Eigenschaft in der Komponente namens id hinzufügen, b.) sie exportieren, c.) meiner Komponente eine ID zuweisen, d.) in meinem CSS, auch wenn ich die Kinder innerhalb eines Tags mit einer zugewiesenen ID in diesem Dokument anspreche, müsste ich es trotzdem in einen :global-Selektor einwickeln.
Ich konnte die Komponente selbst nicht einmal auf meiner Seite *positionieren*, ohne zusätzlichen Boilerplate-Code innerhalb der Komponente hinzuzufügen oder sie in ein weiteres überflüssiges Div zu verpacken – und in beiden Fällen musste ich immer noch einen weiteren :global-Selektor verwenden.
Das Ergebnis ist, dass ich letztendlich alle meine Komponenten in zusätzliche Divs verpackte, was hässlich, unordentlich war und mein HTML aufblähte. Und sie sind sich dessen bewusst, denn sie empfehlen Ihnen nicht nur, dies als Lösung zu tun, sondern sie tun dies auch hinter den Kulissen selbst mit syntaktischem Zucker wie CSS-Variablen-Eigenschaften. Dies kann zu noch mehr Problemen führen, da sie unsichtbare Divs in Ihr HTML einfügen, die Sie tatsächlich mit Ihrem CSS ansprechen können.
Ich stellte einfach fest, dass der Zugriff auf alles innerhalb einer Komponente zum Stylen oder programmatischen Ändern ein Chaos aus zusätzlichem Boilerplate war, das ich einrichten musste. Ich erkannte schließlich, dass ich mit Svelte Zeit verlor, anstatt Zeit zu sparen.
Dennoch bin ich sicher, dass ich nicht jeden Trick oder Ansatz dafür gelernt habe und es vielleicht bessere Wege gibt, aber für mich bot Svelte das Gegenteil einer intuitiven, zugänglichen und benutzerfreundlichen Styling-API.