Sass-Techniken aus der Praxis

Avatar of Buddy Reno
Buddy Reno am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Nachdem ich mehr als 14 Jahre in der Webentwicklungsbranche tätig bin, habe ich gute und schlechte CSS-Codes gesehen und geschrieben. Als ich vor fünf Jahren bei Ramsey Solutions anfing, wurde ich mit Sass bekannt gemacht. Es hat mich umgehauen, wie nützlich es war! Ich habe mich sofort damit beschäftigt und wollte alles darüber lernen. In den letzten fünf Jahren habe ich eine Reihe verschiedener Sass-Techniken und -Muster angewendet und mich in einige verliebt, die, um es mit Apples Worten zu sagen, einfach funktionieren.

In diesem Artikel werde ich eine breite Palette von Themen behandeln

Meiner Erfahrung nach ist das Finden des Gleichgewichts zwischen einfach und komplex die entscheidende Komponente für die Erstellung großartiger Software. Software sollte nicht nur für Menschen einfach zu bedienen sein, sondern auch für Sie und andere Entwickler in Zukunft wartbar. Ich würde diese Techniken als fortgeschritten, aber nicht unbedingt als clever oder absichtlich komplex bezeichnen!

„Jeder weiß, dass Debugging doppelt so schwierig ist wie das Schreiben eines Programms. Wenn Sie also beim Schreiben des Programms so clever wie möglich sind, wie werden Sie es jemals debuggen?“

—Die Elemente der Programmierung und des Stils (2. Auflage), Kapitel 2

In diesem Sinne wollen wir uns zunächst den Sass-Ampersand ansehen.


Die Macht des Ampersands

Es gibt viele verschiedene Namenskonventionen, mit denen Sie Ihre CSS organisieren können. Diejenige, die ich am liebsten verwende, ist SUIT, eine Variation von BEM (was kurz für Block, Element, Modifier steht). Wenn Sie mit SUIT oder BEM nicht vertraut sind, empfehle ich Ihnen, einen Blick darauf zu werfen, bevor Sie fortfahren. Ich werde die SUIT-Konvention im Rest dieses Artikels verwenden.

Welche Namenskonvention Sie auch wählen, die Grundidee ist, dass jedes gestylte Element seinen eigenen Klassennamen erhält, der mit dem Komponentennamen vorangestellt ist. Diese Idee ist wichtig für die Funktionsweise einiger der folgenden Organisationsmethoden. Außerdem ist dieser Artikel beschreibend, nicht vorschreibend. Jedes Projekt ist anders. Sie müssen tun, was für Ihr Projekt und Ihr Team am besten funktioniert.

Der Ampersand ist der Hauptgrund, warum ich SUIT, BEM und ähnliche Konventionen verwende. Er ermöglicht es mir, Verschachtelung und Geltungsbereiche zu nutzen, ohne dass beides durch Spezifität zurückschlägt. Hier ist ein Beispiel. Ohne den Ampersand müsste ich separate Selektoren erstellen, um -title und -content Elemente zu erstellen.

.MyComponent {
  .MyComponent-title {}
}

.MyComponent-content {}

// Compiles to
.MyComponent .MyComponent-title {} // Not what we want. Unnecessary specificity!
.MyComponent-content {} // Desired result

Bei der Verwendung von SUIT möchte ich das zweite Ergebnis für -content so haben, wie ich alle meine Selektoren schreibe. Dazu müsste ich den Namen der Komponente immer wieder wiederholen. Das erhöht die Wahrscheinlichkeit, dass ich den Namen der Komponente beim Schreiben neuer Stile falsch tippe. Es ist auch sehr unübersichtlich, da der Anfang vieler Selektoren ignoriert wird, was dazu führen kann, dass offensichtliche Fehler übersehen werden.

.MyComponent {}
.MyComponent-title {}
.MyComponent-content {}
.MyComponent-author {}
// Etc.

Wenn dies normales CSS wäre, wären wir gezwungen, das oben Genannte zu schreiben. Da wir Sass verwenden, gibt es einen viel besseren Ansatz, indem wir den Ampersand verwenden. Der Ampersand ist erstaunlich, weil er eine Referenz auf den aktuellen Selektor zusammen mit allen Elternelementen enthält.

.A {
  // & = '.A'
  .B {
    // & = '.A .B'
    .C {
      // & = '.A .B .C'
    }
  }
}

Sie können im obigen Beispiel sehen, wie der Ampersand jeden Selektor in der Kette referenziert, während er tiefer in den verschachtelten Code geht. Durch die Nutzung dieser Funktion können wir neue Selektoren erstellen, ohne jedes Mal den Namen der Komponente neu schreiben zu müssen.

.MyComponent {
  &-title {}
  
  &-content {}
}

// Compiles to
.MyComponent {}
.MyComponent-title {}
.MyComponent-content {}

Das ist großartig, weil wir den Ampersand nutzen können, um den Namen der Komponente einmal zu schreiben und den Komponentennamen einfach überall zu referenzieren. Dies verringert die Wahrscheinlichkeit, dass der Komponentennamen falsch geschrieben wird. Außerdem wird das Dokument als Ganzes leichter lesbar, ohne dass .MyComponent überall im Code wiederholt wird.


Es gibt Zeiten, in denen die Komponente ein Variante oder Modifikator benötigt, wie sie in SUIT und BEM genannt werden. Die Verwendung des Ampersand-Musters erleichtert die Erstellung von Modifikatoren.

<div class="MyComponent MyComponent--xmasTheme"></div>
.MyComponent {
  &--xmasTheme {}
}

// Compiles to
.MyComponent {}
.MyComponent--xmasTheme {}

„Aber, was ist mit der Modifizierung von Kindelementen?“, könnten Sie fragen. „Wie werden diese Selektoren erstellt? Der Modifikator ist doch nicht auf jedes Element notwendig, oder?“

Hier können Variablen helfen!

Variablen und Geltungsbereiche

Früher habe ich Modifikatoren auf verschiedene Arten erstellt. Meistens habe ich den speziellen Thema-Namen, den ich beim Modifizieren des Elements anwenden möchte, neu geschrieben.

.MyComponent {
  &-title {
    .MyComponent--xmasTheme & {
    }
  }
  
  &-content {
    .MyComponent--xmasTheme & {
    }
  }
}

// Compiles to
.MyComponent-title {}
.MyComponent--xmasTheme .MyComponent-title {}
.MyComponent-content {}
.MyComponent--xmasTheme .MyComponent-content {}

Das erledigt die Arbeit, aber ich schreibe den Komponentennamen wieder an mehreren Stellen, ganz zu schweigen vom Modifikatornamen. Es gibt definitiv einen besseren Weg, dies zu tun. Hier kommen Sass-Variablen ins Spiel.

Bevor wir Sass-Variablen mit Selektoren untersuchen, müssen wir verstehen, wie sie zugewiesen werden. Sass-Variablen haben einen Geltungsbereich, genau wie in JavaScript, Ruby oder jeder anderen Programmiersprache. Wenn sie außerhalb eines Selektors deklariert werden, ist die Variable nach ihrer Deklaration für jeden Selektor im Dokument verfügbar.

$fontSize: 1.4rem;

.a { font-size: $fontSize; }
.b { font-size: $fontSize; }

Innerhalb eines Selektors deklarierte Variablen sind nur für diesen Selektor und seine Kindelemente zugewiesen.

$fontSize: 1.4rem;

.MyComponent { 
  $fontWeight: 600;
  font-size: $fontSize; 
  
  &-title {
    font-weight: $fontWeight; // Works!
  }
}

.MyComponent2 { 
  font-size: $fontSize; 
  
  &-title {
    font-weight: $fontWeight; // produces an "undefined variable" error
  }
}

Wir wissen, dass Variablen Font-Namen, Ganzzahlen, Farben usw. speichern können. Wussten Sie, dass sie auch Selektoren speichern können? Mit String-Interpolation können wir neue Selektoren mit der Variable erstellen.

// Sass string interpolation syntax is #{VARIABLE} 
$block: ".MyComponent";

#{$block} {
  &-title {
    #{$block}--xmasTheme & {
    }
  }
}

// Compiles to
.MyComponent {}
.MyComponent-title {}
.MyComponent--xmasTheme .MyComponent-title {}

Das ist cool, aber die Variable hat einen globalen Geltungsbereich. Wir können das beheben, indem wir die Variable $block innerhalb der Komponentendeklaration erstellen, wodurch sie auf diese Komponente beschränkt wird. Dann können wir die Variable $block in anderen Komponenten wiederverwenden. Dies hilft, den Thema-Modifikator DRY zu halten.

.MyComponent {
  $block: '.MyComponent';
  
  &-title {
    #{$block}--xmasTheme & {
    }
  }
  
  &-content {
    #{$block}--xmasTheme & {
    }
  }
}

// Compiles to
.MyComponent {}
.MyComponent-title {}
.MyComponent--xmasTheme .MyComponent-title {}
.MyComponent-content {}
.MyComponent--xmasTheme .MyComponent-content {}

Das ist näher dran, aber wieder müssen wir den Thema-Namen immer wieder schreiben. Lass uns das auch in einer Variable speichern!

.MyComponent {
  $block: '.MyComponent';
  $xmasTheme: '.MyComponent--xmasTheme';
  
  &-title {
    #{$xmasTheme} & {
    }
  }
}

Das ist viel besser! Wir können das aber noch weiter verbessern. Variablen können auch den Wert des Ampersands speichern!

.MyComponent {
  $block: &;
  $xmasTheme: #{&}--xmasTheme;
  
  &-title {
    #{$xmasTheme} & {
    }
  }
}

// Still compiles to
.MyComponent {}
.MyComponent-title {}
.MyComponent--xmasTheme .MyComponent-title {}

Jetzt reden wir aber! Das „Zwischenspeichern“ des Selektors mit dem Ampersand ermöglicht es uns, unsere Modifikatoren oben zu erstellen und die Thema-Modifikationen bei dem Element zu belassen, das sie modifiziert.

„Sicher, das funktioniert auf der obersten Ebene“, sagen Sie. „Aber was ist, wenn man tief verschachtelt ist, wie acht Ebenen tief?“ Sie stellen gute Fragen.

Unabhängig davon, wie tief die Verschachtelung ist, funktioniert dieses Muster immer, da der Hauptkomponentennamen dank der SUIT-Namenskonvention und der Ampersand-Kombination nie an die Kindelemente angehängt wird.

.MyComponent { 
  $block: &;
  $xmasTheme: #{&}--xmasTheme;
  
  &-content {
    font-size: 1.5rem;
    color: blue;
    
    ul {
      li {
        strong {
          span {
            &::before {
              background-color: blue;
              
              #{$xmasTheme} & {
                background-color: red;
              }
            }
          }
        }
      }
    }
  }
}

// Compiles to 
.MyComponent-content {
  font-size: 1.5rem;
  color: blue;
}

.MyComponent-content ul li strong span::before {
  background-color: blue;
}

/*
* The theme is still appended to the beginning of the selector!
* Now, we never need to write deeply nested Sass that's hard to maintain and 
* extremely brittle: https://css-tricks.de/sass-selector-combining/
*/
.MyComponent--xmasTheme .MyComponent-content ul li strong span::before {
  background-color: red;
}

Die Codeorganisation ist der Hauptgrund, warum ich dieses Muster verwende.

  • Es ist relativ DRY
  • Es unterstützt den „Opt-in“-Ansatz, der Modifikatoren bei den Elementen belässt, die sie modifizieren
  • Das Benennen von Dingen ist schwierig, aber dies ermöglicht uns die Wiederverwendung gängiger Elementnamen wie „title“ und „content“
  • Es ist einfach, einen Modifikator zu einer Komponente hinzuzufügen, indem die Modifikator-Klasse auf der Elternkomponente platziert wird

„Hhhmmmmm… wird das nicht schwer zu lesen, wenn man viele verschiedene Komponenten erstellt? Woher weiß man, wo man sich befindet, wenn alles &-title und &-content heißt?“

Sie stellen weiterhin tolle Fragen. Wer hat gesagt, dass der Quellcode-Sass in einer Datei sein muss? Wir können diese Komponenten importieren, also kommen wir zu diesem Thema!

Die Bedeutung von Imports

Quelle: @Julien_He

Eine der besten Funktionen von Sass ist @import. Wir können separate Sass-Dateien (Partials) erstellen und sie in andere Sass-Dateien importieren, die zusammen kompiliert werden, wobei die importierte Datei an der Stelle ihrer Importierung platziert wird. Dies erleichtert die Bündelung verwandter Stile für Komponenten, Dienstprogramme usw. und das Einbinden in eine einzige Datei. Ohne @import müssten wir separate CSS-Dateien verlinken (was zu zahlreichen Netzwerkanfragen führt, was schlecht ist) oder alles in einer einzigen Stieltabelle schreiben (was schwer zu navigieren und zu warten ist).

.Component1 {
  &-title {}
  &-content {}
  &-author {}
}

.Component2 {
  &-title {}
  &-content {}
  &-author {}
}

.Component3 {
  &-title {}
  &-content {}
  &-author {}
}

.Component4 {
  &-title {}
  &-content {}
  &-author {}
}

.Component5 {
  &-title {}
  &-content {}
  &-author {}
}

// A couple of hundred lines later...

.Component7384 {
  &-title {}
  &-content {}
  &-author {}
}

// WHERE AM I?

Eine der beliebtesten Methoden zur Organisation von Sass-Dateien ist das 7-1 Muster. Das sind sieben verschiedene Ordner mit Sass-Dateien, die in eine einzige Sass-Datei importiert werden.

Diese Ordner sind

  • abstrakte
  • Basis
  • Komponenten
  • Layout
  • Seiten
  • Themen
  • Lieferant

Verwenden Sie @import, um jede Sass-Datei in diesen Ordnern in eine Haupt-Sass-Datei zu ziehen. Wir möchten sie in der folgenden Reihenfolge importieren, um einen guten Geltungsbereich beizubehalten und Konflikte während der Kompilierung zu vermeiden

  1. abstrakte
  2. Lieferant
  3. Basis
  4. Layout
  5. Komponenten
  6. Seiten
  7. Themen
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';

@import 'vendors/some-third-party-component';

@import 'base/normalize';

@import 'layout/navigation';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';

@import 'components/buttons';
@import 'components/hero';
@import 'components/pull-quote';

@import 'pages/home';
@import 'pages/contact';

@import 'themes/default';
@import 'themes/admin';

Sie möchten vielleicht nicht alle diese Ordner verwenden (ich persönlich verwende den Themenordner nicht, da ich Themen bei ihren Komponenten belasse), aber die Idee, alle Stile in verschiedene Dateien zu trennen, erleichtert die Wartung und das Auffinden von Code.

Weitere Vorteile dieser Vorgehensweise

  • Kleine Komponenten sind leichter zu lesen und zu verstehen
  • Das Debugging wird einfacher
  • Es ist klarer zu erkennen, wann eine neue Komponente erstellt werden soll – zum Beispiel, wenn eine einzelne Komponentendatei zu lang wird oder die Selektorkette zu komplex ist
  • Dies betont die Wiederverwendung – zum Beispiel kann es sinnvoll sein, drei Komponentendateien, die im Wesentlichen dasselbe tun, zu einer Komponente zu verallgemeinern

Apropos Wiederverwendung, es gibt schließlich Muster, die oft verwendet werden. Dann können wir zu Mixins greifen.

Mixin' es auf

Mixins sind eine großartige Möglichkeit, Stile projektweit wiederzuverwenden. Lassen Sie uns eine einfache Mixin erstellen und ihr dann ein wenig Intelligenz verleihen.

Der Designer, mit dem ich regelmäßig zusammenarbeite, legt immer font-size, font-weight und line-height auf bestimmte Werte fest. Ich fand mich dabei wieder, alle drei jedes Mal zu tippen, wenn ich die Schriftarten für eine Komponente oder ein Element anpassen musste, also habe ich eine Mixin erstellt, um diese Werte schnell festzulegen. Es ist wie eine kleine Funktion, die ich verwenden kann, um diese Eigenschaften zu definieren, ohne sie vollständig ausschreiben zu müssen.

@mixin text($size, $lineHeight, $weight) {
  font-size: $size;
  line-height: $lineHeight;
  font-weight: $weight;
}

An diesem Punkt ist die Mixin ziemlich einfach – sie ähnelt einer Funktion in JavaScript. Da ist der Name der Mixin (text) und sie nimmt drei Argumente entgegen. Jedes Argument ist an eine CSS-Eigenschaft gebunden. Wenn die Mixin aufgerufen wird, kopiert Sass die Eigenschaften und übergibt die Argumentwerte.

.MyComponent {
  @include text(18px, 27px, 500);
}

// Compiles to
.MyComponent {
  font-size: 18px;
  line-height: 27px;
  font-weight: 500;
}

Obwohl es eine gute Demonstration ist, ist diese spezielle Mixin etwas begrenzt. Sie geht davon aus, dass wir immer die Eigenschaften font-size, line-height und font-weight verwenden wollen, wenn sie aufgerufen wird. Lassen Sie uns also die if-Anweisung von Sass verwenden, um die Ausgabe zu steuern.

@mixin text($size, $lineHeight, $weight) {
  // If the $size argument is not empty, then output the argument
  @if $size != null {
    font-size: $size;
  }
  
  // If the $lineHeight argument is not empty, then output the argument
  @if $lineHeight != null {
    line-height: $lineHeight;
  }
  
  // If the $weight argument is not empty, then output the argument
  @if $weight != null {
    font-weight: $weight;
  }
}

.MyComponent {
  @include text(12px, null, 300);
}

// Compiles to
.MyComponent {
  font-size: 12px;
  font-weight: 300;
}

Das ist besser, aber noch nicht ganz perfekt. Wenn ich versuche, die Mixin ohne die Verwendung von null als Parameter für die Werte zu verwenden, die ich nicht verwenden möchte oder die ich nicht angebe, generiert Sass einen Fehler

.MyComponent {
  @include text(12px, null); // left off $weight
}

// Compiles to an error:
// "Mixin text is missing argument $weight."

Um dies zu umgehen, können wir Standardwerte für die Parameter hinzufügen, sodass wir sie beim Funktionsaufruf weglassen können. Alle optionalen Parameter müssen nach allen erforderlichen Parametern deklariert werden.

// We define `null` as the default value for each argument
@mixin text($size: null, $lineHeight: null, $weight: null) {
  @if $size != null {
    font-size: $size;
  }
  
  @if $lineHeight != null {
    line-height: $lineHeight;
  }
  
  @if $weight != null {
    font-weight: $weight;
  }
}

.MyComponent {
  &-title {
    @include text(16px, 19px, 600);
  }
  
  &-author {
    @include text($weight: 800, $size: 12px);
  }
}

// Compiles to
.MyComponent-title {
  font-size: 16px;
  line-height: 19px;
  font-weight: 600;
}

.MyComponent-author {
  font-size: 12px;
  font-weight: 800;
}

Standard-Argumentwerte machen die Mixin nicht nur einfacher zu verwenden, sondern wir gewinnen auch die Möglichkeit, Parameter zu benennen und ihnen Werte zu geben, die häufig verwendet werden. In Zeile 21 oben wird die Mixin mit den Argumenten in falscher Reihenfolge aufgerufen, aber da die Werte auch aufgerufen werden, weiß die Mixin, wie sie sie anwenden soll.


Es gibt eine spezielle Mixin, die ich täglich benutze: min-width. Ich bevorzuge es, alle meine Websites mobile first zu erstellen, also im Grunde mit dem kleinsten Viewport im Auge. Wenn der Viewport breiter wird, definiere ich Breakpoints, um das Layout und den Code dafür anzupassen. Hier greife ich zur min-width Mixin.

// Let's name this "min-width" and take a single argument we can
// use to define the viewport width in a media query.
@mixin min-width($threshold) {
  // We're calling another function (scut-rem) to convert pixels to rem units.
  // We'll cover that in the next section.
  @media screen and (min-width: scut-rem($threshold)) {
    @content;
  }
}

.MyComponent {
  display: block;
  
  // Call the min-width mixin and pass 768 as the argument.
  // min-width passes 768 and scut-rem converts the unit.
  @include min-width(768) {
    display: flex;
  }
}

// Compiles to 
.MyComponent {
  display: block;
}

@media screen and (min-width: 48rem) {
  .MyComponent {
    display: flex;
  }
}

Hier gibt es ein paar neue Ideen. Die Mixin hat eine verschachtelte Funktion namens @content. Im .MyComponent-Klassens werden wir also nicht mehr die Mixin allein aufrufen, sondern auch einen Codeblock, der innerhalb der generierten Media-Abfrage ausgegeben wird. Der resultierende Code wird dort kompiliert, wo @content aufgerufen wird. Dies ermöglicht es der Mixin, die @media-Deklaration zu übernehmen und trotzdem benutzerdefinierten Code für diesen speziellen Breakpoint zu akzeptieren.

Ich binde die Mixin auch innerhalb der .MyComponent-Deklaration ein. Manche Leute befürworten, alle responsiven Aufrufe in einer separaten Stieltabelle zu belassen, um die Anzahl der @media-Aufrufe in einer Stieltabelle zu reduzieren. Persönlich bevorzuge ich es, alle Variationen und Änderungen, die eine Komponente durchlaufen kann, bei der Deklaration dieser Komponente zu belassen. Es erleichtert die Verfolgung dessen, was passiert, und hilft bei der Fehlersuche in der Komponente, wenn etwas schiefgeht, anstatt mehrere Dateien zu durchsuchen.

Haben Sie die scut-rem-Funktion darin bemerkt? Das ist eine Sass-Funktion aus einer Sass-Bibliothek namens Scut, erstellt von David The Clark. Sehen wir uns an, wie das funktioniert.

Funktional werden

Eine Funktion unterscheidet sich von einer Mixin dadurch, dass Mixins dazu gedacht sind, gängige Eigenschaftsgruppen auszugeben, während eine Funktion Eigenschaften basierend auf Argumenten modifiziert, die ein neues Ergebnis zurückgeben. In diesem Fall nimmt scut-rem einen Pixelwert und wandelt ihn in einen Rem-Wert um. Dies ermöglicht es uns, in Pixeln zu denken, während wir hinter den Kulissen mit Rem-Einheiten arbeiten, um all diese Berechnungen zu vermeiden.

Ich habe scut-rem in diesem Beispiel vereinfacht, da es einige zusätzliche Funktionen enthält, die Schleifen und Listen verwenden, die außerhalb des Rahmens dessen liegen, was wir hier behandeln. Sehen wir uns die Funktion in ihrer Gesamtheit an und zerlegen Sie sie dann Schritt für Schritt.

// Simplified from the original source
$scut-rem-base: 16 !default;

@function scut-strip-unit ($num) {
  @return $num / ($num * 0 + 1);
}

@function scut-rem ($pixels) {
  @return scut-strip-unit($pixels) / $scut-rem-base * 1rem;
}

.MyComponent {
  font-size: scut-rem(18px);  
}

// Compiles to
.MyComponent {
  font-size: 1.125rem;
}

Das erste, was zu beachten ist, ist die Deklaration in Zeile 2. Sie verwendet !default bei der Deklaration einer Variable, was Sass anweist, den Wert auf 16 zu setzen, es sei denn, diese Variable ist bereits definiert. Wenn also eine Variable früher in der Stieltabelle mit einem anderen Wert deklariert wurde, wird sie hier nicht überschrieben.

$fontSize: 16px;
$fontSize: 12px !default;

.MyComponent {
  font-size: $fontSize;
}

// Compiles to
.MyComponent {
  font-size: 16px;
}

Das nächste Puzzleteil ist scut-strip-unit. Diese Funktion nimmt einen px-, rem-, Prozent- oder anderen suffigierten Wert und entfernt die Einheit. Der Aufruf von scut-strip-unit(12px) gibt 12 anstelle von 12px zurück. Wie funktioniert das? In Sass wird eine Einheit geteilt durch eine Einheit desselben Typs die Einheit entfernen und die Ziffer zurückgeben.

12px / 1px = 12

Jetzt, wo wir das wissen, sehen wir uns die scut-strip-unit-Funktion noch einmal an.

@function scut-strip-unit ($num) {
  @return $num / ($num * 0 + 1);
}

Die Funktion nimmt eine Einheit entgegen und teilt sie durch 1 derselben Einheit. Wenn wir also 12px übergeben, würde die Funktion wie folgt aussehen: @return 12px / (12px * 0 + 1). Gemäß der Reihenfolge der Operationen wertet Sass zuerst das aus, was in den Klammern steht. Sass ignoriert geschickt das px-Label, wertet den Ausdruck aus und hängt px wieder an, sobald es fertig ist: 12 * 0 + 1 = 1px. Die Gleichung lautet nun 12px / 1px, was bekanntermaßen 12 ergibt.

Warum ist das für scut-rem wichtig? Sehen wir es uns noch einmal an.

$scut-rem-base: 16 !default;

@function scut-rem ($pixels) {
  @return scut-strip-unit($pixels) / $scut-rem-base * 1rem;
}

.MyComponent {
  font-size: scut-rem(18px);  
}

In Zeile 4 entfernt die Funktion scut-strip-unit px vom Argument und gibt 18 zurück. Die Basisvariable ist gleich 16, was die Gleichung in 18 / 16 * 1rem umwandelt. Denken Sie daran, Sass ignoriert jede Einheit bis zum Ende der Gleichung, also 18 / 16 = 1,125. Dieses Ergebnis multipliziert mit 1rem ergibt 1,125rem. Da Scut die Einheit vom Argument entfernt, können wir scut-rem mit einheitenlosen Werten aufrufen, wie z. B. scut-rem(18).

Ich schreibe nicht viele Funktionen, da ich versuche, die von mir erstellten Dinge so einfach wie möglich zu halten. Die Fähigkeit, einige komplexe Konvertierungen mit etwas wie scut-rem durchzuführen, ist jedoch hilfreich.

Die Selektorreihenfolge, die Platzhalter durcheinanderbringen

Ende ich dort, wo ich glaube, dass es CSS ist?

Seien Sie vorsichtig, was Sie erweitern

Ich habe versucht, einige Beispiele zu schreiben, um zu demonstrieren, warum die Verwendung von @extend problematisch sein kann, aber ich habe sie so wenig verwendet, dass ich keine vernünftigen Beispiele erstellen kann. Als ich Sass zum ersten Mal lernte, war ich von Teamkollegen umgeben, die bereits die Prüfungen und Schwierigkeiten durchgemacht hatten. Mein Freund Jon Bebee hat einen äußerst ausgezeichneten Artikel darüber geschrieben, wie @extend Sie in Schwierigkeiten bringen kann. Es ist eine schnelle Lektüre und die Zeit wert, also werde ich warten.

Über diese Platzhalter…

Jon schlägt die Verwendung von Platzhaltern als Lösung für das Problem vor, das er darstellt: Platzhalter geben keinen Code aus, bis sie mit @extend verwendet werden.

// % denotes an extended block
%item {
  display: block;
  width: 50%;
  margin: 0 auto;
}

.MyComponent {
  @extend %item;
  color: blue;
}

// Compiles to
.MyComponent {
  display: block;
  width: 50%;
  margin: 0 auto;
}

.MyComponent {
  color: blue;
}

Okay, warte. Es hat also .MyComponent zweimal ausgegeben? Warum hat es die Selektoren nicht einfach kombiniert?

Das sind die Fragen, die ich hatte, als ich anfing, Platzhalter zu verwenden (und sie dann anschließend wieder einstellte). Der Hinweis ist der Name selbst. Platzhalter halten einfach eine Referenz auf die Stelle in der Stieltabelle, an der sie deklariert wurden. Während eine Mixin die Eigenschaften an den Ort kopiert, an dem sie verwendet wird, kopieren Platzhalter den Selektor an den Ort, an dem der Platzhalter definiert wurde. Infolgedessen kopiert es den .MyComponent-Selektor und platziert ihn dort, wo %item deklariert ist. Betrachten Sie das folgende Beispiel

%flexy {
  display: flex;
}

.A {
  color: blue;
}

.B {
  @extend %flexy;
  color: green;
}

.C {
  @extend %flexy;
  color: red;
}

// Compiles to
.B, .C {
  display: flex;
}

.A {
  color: blue;
}

.B {
  color: green;
}

.C {
  color: red;
}

Auch wenn B und C weiter unten in der Stieltabelle deklariert sind, platziert der Platzhalter die erweiterten Eigenschaften bis dorthin, wo er ursprünglich deklariert wurde. Das ist in diesem Beispiel keine große Sache, da es sich sehr nah an der Quelle befindet, wo es verwendet wird. Wenn wir uns jedoch an etwas wie das 7-1 Muster halten, das wir zuvor behandelt haben, dann würden Platzhalter in einem Partial im abstrakten Ordner definiert werden, was eine der ersten importierten Dateien ist. Das platziert viel Stil zwischen der Stelle, an der die Erweiterung beabsichtigt ist, und der Stelle, an der sie tatsächlich verwendet wird. Das kann schwer zu warten und auch schwer zu debuggen sein.

Sass Guidelines (natürlich) macht eine gute Arbeit bei der Abdeckung von Platzhaltern und Erweiterung und ich empfehle, sie zu lesen. Sie erklärt nicht nur die Erweiterungsfunktion, sondern plädiert am Ende auch dagegen.

Die Meinungen scheinen extrem gespalten zu sein bezüglich der Vorteile und Probleme von @extend, bis zu dem Punkt, an dem viele Entwickler, einschließlich mir selbst, dagegen plädiert haben, […]


Es gibt viele weitere Features von Sass, die ich hier nicht behandelt habe, wie Schleifen und Listen, aber ich habe mich ehrlich gesagt nicht so sehr auf diese Features verlassen wie auf die, die wir in diesem Artikel behandelt haben. Werfen Sie einen Blick in die Sass-Dokumentation, wenn auch nur, um zu sehen, was die Dinge tun. Sie finden vielleicht nicht sofort eine Verwendung für alles, aber eine Situation kann sich ergeben und dieses Wissen in der Hinterhand zu haben, ist unbezahlbar.

Lassen Sie mich wissen, wenn ich etwas übersehen oder falsch gemacht habe! Ich bin immer offen für neue Ideen und würde mich freuen, es mit Ihnen zu besprechen!

Weitere Lektüre