So verwenden Sie native CSS-Mixins statt Sass
Erfahren Sie, wie Sie Sass-Mixins mit @mixin und @apply in natives CSS übertragen, Parameter nutzen und erkennen, welche Funktionen weiterhin Sass erfordern.
Ein natives CSS-Mixin ist ein benannter Block von Deklarationen. Sie definieren es mit @mixin --name und fügen es mit @apply --name in eine Stilregel ein. Damit ist es das browserseitige Gegenstück zu @mixin und @include aus Sass.
Wenn Ihre Stylesheets bereits Custom Properties und natives Nesting nutzen, sind die paar gemeinsam genutzten Mixins in einem _mixins.scss-Partial womöglich der einzige Grund, warum Sie noch Sass einsetzen. Dieser Artikel portiert ein reales Mixin nach nativem CSS, stellt beide Versionen gegenüber und zeigt, welche Arten von Mixins sich nicht umstellen lassen.
Das Wichtigste in Kürze
- Native CSS-Mixins werden mit
@mixin --namedefiniert und mit@apply --nameverwendet. Die Namen sind Dashed Idents, und@applyübernimmt die Aufgabe von@includeaus Sass. - Sass kopiert die Deklarationen eines Mixins zur Kompilierzeit in jede Regel, die es einbindet. Ein natives Mixin wird dagegen vom Browser expandiert, sodass das ausgelieferte Stylesheet nur eine einzige Definition enthält.
- Laut MDN unterstützt kein Browser CSS-Mixins standardmäßig. Sie sind daher nicht Baseline, und Sass bleibt die Wahl für den Produktiveinsatz.
- Für Mixins, die auf Sass-Maps,
@each- oder@for-Schleifen,@if/@else-Verzweigungen oder Berechnungen zur Build-Zeit angewiesen sind, gibt es kein natives Äquivalent.
Das Sass-Mixin, das Sie bereits haben
Ein cover-Mixin fixiert ein Element an allen vier Kanten seines positionierten Vorfahren. Es ist so ziemlich das einfachste Mixin, das es gibt, und eignet sich daher gut als Testfall. Hier wird es zweimal verwendet: einmal für einen Backdrop und einmal für ein Overlay per Pseudo-Element. (Mehr Hintergrundwissen zur Sass-Seite finden Sie in diesem Leitfaden zu SCSS-Mixins.)
@mixin cover {
position: absolute;
inset: 0;
}
.dialog-backdrop {
@include cover;
background: rgb(0 0 0 / 0.6);
}
.media-card.is-loading::after {
@include cover;
content: "";
background: rgb(255 255 255 / 0.7);
}
Die Mixin-Definition allein erzeugt kein CSS. Jedes @include kopiert die Deklarationen in die aufrufende Regel:
.dialog-backdrop {
position: absolute;
inset: 0;
background: rgb(0 0 0 / 0.6);
}
.media-card.is-loading::after {
position: absolute;
inset: 0;
content: "";
background: rgb(255 255 255 / 0.7);
}
Je mehr Regeln das Mixin einbinden, desto mehr Kopien dieser beiden Deklarationen landen in der Ausgabe.
Die Umstellung auf native CSS-Mixins im direkten Vergleich
Ein Sass-Mixin, das nur Deklarationen enthält, lässt sich in drei mechanischen Schritten nach nativem CSS portieren: Stellen Sie dem Namen zwei Bindestriche voran, machen Sie aus $-Parametern ---Parameter und ersetzen Sie @include durch @apply.
Sass
@mixin cover {
position: absolute;
inset: 0;
}
.dialog-backdrop {
@include cover;
background: rgb(0 0 0 / 0.6);
}
Natives CSS
@mixin --cover {
position: absolute;
inset: 0;
}
.dialog-backdrop {
@apply --cover;
background: rgb(0 0 0 / 0.6);
}
@apply tritt an die Stelle von @include, und der Mixin-Name muss ein Dashed Ident sein. Da der Browser die Expansion übernimmt, enthält das ausgelieferte Stylesheet nur eine einzige Definition von --cover. Der Rumpf besteht ausschließlich aus Deklarationen, ohne @result-Wrapper, denn die CSSWG hat beschlossen, @result aus Mixins zu streichen. Der Entwurf selbst weist darauf hin, dass Mixins weit weniger ausgereift sind als Custom Functions – die Syntax kann sich also noch ändern.
Browser-Unterstützung für CSS-Mixins
Native CSS-Mixins sind nicht produktionsreif. Der MDN-Leitfaden zu Custom Functions und Mixins gibt an, dass kein Browser Mixins standardmäßig unterstützt; das Feature ist also nicht Baseline. Chromium ist den anderen Engines voraus: Dort wurde ein Intent to Prototype für CSS-Mixins eingereicht, die Arbeit daran ist jedoch experimentell.
Auch als Progressive Enhancement taugen native CSS-Mixins nicht. Die Fehlerbehandlung in CSS verwirft Konstrukte, die der Parser nicht versteht. Ein Browser ohne Unterstützung überspringt also @apply, und ein Element, das position und inset nur über das Mixin erhält, bekommt keine der beiden Eigenschaften. Behalten Sie für den Produktiveinsatz die Sass-Version bei und testen Sie native Mixins in einer reinen .css-Datei, die der Sass-Compiler nie zu sehen bekommt.
Mixin-Parameter portieren
Sass-Mixin-Parameter, die einfache Werte übergeben, lassen sich problemlos auf native CSS-Mixins übertragen. Mixins, die zur Build-Zeit Werte berechnen, verzweigen oder Schleifen durchlaufen, dagegen nicht. Hier ist cover mit einem Inset-Argument:
// Sass
@mixin cover($inset: 0) {
position: absolute;
inset: $inset;
}
.frame::before { @include cover(0.5rem); content: ""; }
/* Native */
@mixin --cover(--inset) {
position: absolute;
inset: var(--inset);
}
.frame::before { @apply --cover(0.5rem); content: ""; }
Jeder Parameter wird innerhalb des Mixin-Rumpfs zu einer privaten Property, die Sie mit var() auslesen. Andere Styles auf der Seite können sie nicht sehen. Fallbacks in var() funktionieren im Rumpf genauso wie in jeder anderen Deklaration. Der Entwurf CSS Custom Functions and Mixins definiert außerdem eine eigene Syntax, um Parameter zu typisieren und mit Standardwerten zu versehen. Prüfen Sie die aktuelle Form im Entwurf und gehen Sie nicht davon aus, dass sich ein Fallback exakt wie ein Standardwert verhält. Der First Public Working Draft vom 15. Mai 2025 verlangte Klammern selbst bei Mixins ohne Parameter; spätere Entwürfe erlauben es, sie wegzulassen. Ältere Prototyp-Builds erforderten @mixin --a() und @apply --a();, daher werden Ihnen beide Schreibweisen begegnen.
Für folgende Sass-Mixin-Features gibt es kein natives CSS-Äquivalent:
@each- und@for-Schleifen@if/@else-Verzweigungen und@error- Maps und
map.getaus demsass:map-Modul - Berechnungen zur Build-Zeit wie
math.divoder Einheitenumrechnungen
Das Breakpoint-Mixin zeigt, wo die Grenze verläuft:
@use "sass:map";
$breakpoints: (sm: 40rem, md: 64rem);
@mixin bp($name) {
@if not map.has-key($breakpoints, $name) {
@error "Unknown breakpoint: #{$name}";
}
@media (min-width: map.get($breakpoints, $name)) {
@content;
}
}
Die Spezifikation definiert @contents als Gegenstück zu @content aus Sass. Grundsätzlich kann ein natives Mixin also einen Block vom Aufrufer entgegennehmen und in @media einbetten. Nicht portierbar sind der Map-Lookup, der @error-Zweig und die variable Breite innerhalb der Media Query.
Was bringen native CSS-Mixins?
Native CSS-Mixins bieten gegenüber Sass-Mixins zwei Vorteile: keinen Build-Schritt und Argumente, die im Browser statt zur Kompilierzeit aufgelöst werden. Zum ersten Punkt: Der Browser liest @mixin und @apply direkt, sodass das CSS, das Sie schreiben, auch das CSS ist, das Sie ausliefern.
Der zweite Vorteil ist subtiler. Auch Sass kann var()-Referenzen ausgeben, sodass ein Sass-Mixin Deklarationen erzeugen kann, die zur Laufzeit auf Custom Properties reagieren. Was Sass jedoch nicht kann, ist ein Argument nach der Kompilierung zu ändern: cover(0.5rem) wird während des Builds einmalig zu inset: 0.5rem. Native Mixins werden im Browser aufgelöst, und die Spezifikation sieht eine Behandlung von Argumenten vor, deren Werte vom jeweiligen Element abhängen, auf das das Mixin angewendet wird. Dieses Verhalten ist in der Spezifikation festgelegt, aber noch in keiner ausgelieferten Engine umgesetzt. Custom Functions – ein verwandtes Feature aus demselben Modul, das mit @function definiert wird – geben einen einzelnen Wert zurück, während Mixins einen Block von Deklarationen liefern.
Wann sollten Sie bei Sass bleiben?
Mixins, die nur Deklarationen enthalten – etwa Cover, Zentrierung und Visually-hidden –, lassen sich problemlos portieren. Mixins, die Selektoren generieren, über Listen iterieren oder zur Build-Zeit Werte berechnen, dagegen nicht.
| Mixin | Sauber portierbar? | Was sich ändert | Warum nicht |
|---|---|---|---|
| Cover / inset | Ja | ---Name, @apply, var(--inset) | – |
| Visually-hidden | Ja | ---Name, @apply | – |
| Zentrierung | Ja | ---Name, @apply | – |
| Breakpoints | Nein | Einbetten von Blöcken per @contents grundsätzlich möglich | Map-Lookup, @error, variable Breite in der Media Query |
Setzen Sie @mixin und @include aus Sass weiterhin für Schleifen ein, die Utility-Klassen generieren, sowie für Map-gesteuerte Tokens und Breakpoint-Helfer. Und verwenden Sie Sass für alles im Produktivbetrieb, bis Mixins standardmäßig in Browsern verfügbar sind.
Fazit
Die Umstellung eines reinen Deklarations-Mixins wie cover auf native Syntax ist schnell erledigt und weitgehend mechanisch. Wann sich der Wechsel lohnt, hängt jedoch von der Browser-Unterstützung ab – und die gibt es noch nicht. Ein praktischer nächster Schritt: Teilen Sie Ihre Mixins in zwei Gruppen ein – reine Deklarations-Mixins und solche, die auf Sass-Logik angewiesen sind. Schreiben Sie die erste Gruppe in einer separaten .css-Datei neu und testen Sie sie in einem experimentellen Chromium-Build. Behalten Sie die Sass-Versionen bei, bis MDN eine standardmäßige Unterstützung ausweist.
FAQs
Wie teste ich native CSS-Mixins in Chrome?
Chromiums Mixin-Prototyp ist hinter dem Feature-Flag CSSMixins verborgen. Um ihn auszuprobieren, starten Sie Chrome Canary über die Kommandozeile mit dem Argument --enable-features=CSSMixins. Die Implementierung ist unvollständig und ändert sich, während die CSSWG offene Fragen der Spezifikation klärt. Manche Beispiele können daher fehlschlagen oder sich anders verhalten als im Entwurf beschrieben. Nutzen Sie sie nur für Experimente und Feedback zur Spezifikation, niemals für produktive Styles.
Warum kann ich eine Sass-Breakpoint-Variable in einer Media Query nicht durch var() ersetzen?
Die Funktion var() funktioniert nur innerhalb von Property-Werten, und Bedingungen in Media Queries sind keine Property-Werte. Custom Properties werden für jedes Element über die Kaskade aufgelöst, während eine Media Query gegen den Viewport oder das Gerät ausgewertet wird und nicht gegen ein bestimmtes Element. Eine Bedingung wie min-width: var(--md) ist daher ungültig, und eine in einer Variablen gespeicherte Breakpoint-Breite lässt sich nicht aus Sass in eine native Media Query übertragen.
Kann ein natives CSS-Mixin verschachtelte Selektoren oder Media Queries enthalten?
Ja, laut Spezifikation. Der Entwurf CSS Custom Functions and Mixins erlaubt im Mixin-Rumpf verschachtelte Stilregeln, etwa einen Block mit Ampersand und ::after, sowie bedingte Regeln wie @media – ähnlich wie ein Sass-Mixin sie ausgeben kann. Da kein Browser Mixins standardmäßig ausliefert, beschreibt dies das von der Spezifikation vorgesehene Verhalten und nicht etwas, das in einer stabilen Engine läuft.
Ist postcss-mixins dasselbe wie native CSS-Mixins?
Nein. Das Plugin postcss-mixins definiert ein Mixin mit @define-mixin, ruft es mit @mixin auf und verwendet Parameter mit Dollarzeichen, die zur Build-Zeit expandiert werden. Natives CSS definiert ein Mixin mit @mixin, ruft es mit @apply auf, und der Browser übernimmt die Expansion. Das Schlüsselwort @mixin hat in beiden Systemen also die entgegengesetzte Bedeutung. Bei der Umstellung von postcss-mixins auf die native Syntax müssen Sie daher sowohl die Definitionen als auch die Aufrufstellen neu schreiben.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Star on GitHub12k