SCSS: The Ampersand & You

Bildnachweis: http://sierrawrrr.tumblr.com/post/45932456229/http-whrt-it-wobsdm

Seit ungefähr 6 Jahren schreibe ich CSS mit mit SCSS. Neben den offensichtlichen Vorteilen, wie Variablen und Nesting 1, ist dass von mir am meisten genutzte und geschätzte Feature eigentlich das Et-Zeichen.

Das Et-Zeichen, auch Und-Zeichen, ist ein in bestimmten Fällen verwendbares Ersatzzeichen für das Wort „und“ (lat. et). Es wird umgangssprachlich auch als Kaufmanns-Und, kaufmännisches Und oder Firmen-Und bezeichnet [...]Wikipedia

In diesem Artikel werde ich mich in der Benennung wohl einfach mit einem einfachen & oder dem englischen Begriff Ampersand begnügen.

Nesting (Verschachtelung)

Kurz etwas Grundlagenwiederholung: Den häufigsten Einsatzzweck des & findet man oft im Kontext der Verschachtelung. Aber: Verschachtelung in SCSS ist mit Bedacht zu nutzen, richtig angewendet ist es aber ein mächtiges Werkzeug. Das funktioniert üblicherweise so:


.myClass {
    .mySubClass {
    // some css declarations
    }
}

Dieses Snippet kann man auch mit & schreiben:


.myClass {
    & .mySubClass {
        // some css declarations
    }
}

Beide Schreibweisen führen zu demselben CSS Ergebnis. Beides ergibt:

.myClass .mySubClass {
    // some css declarations
}

Warum also hier & nutzen? Scheinbar ergeben sich hier keinerlei Vorteile und das ist auch richtig so. Das erste Beispiel ohne & ist nur eine Shorthand Schreibweise für das Nesting mit &. Wir nutzen also & um ein vielfaches mehr als uns eigentlich bewusst ist. 2

Joining Classes - CSS Klassen miteinander verbinden

Interessanter wird es bei dem Verknüpfen von Klassennamen. Dies sieht üblicherweise folgendermassen aus:

.base {  
    background: white;  
}  
.base.modifier1 {  
    background: green;  
}

.base.modifier1 {  
    background: red;  
}  

Funktioniert, ist aber nicht schön - denn SCSS bietet da doch einen besseren Weg. Fügen wir es mit einem & zusammen und verzichten auf das Spaaaaaace nach dem & können Klassen direkt miteinander verknüpft werden.


.base {  
    background: white;

    &.modifier1 {  
        background: green;  
    }

    &.modifier2 {  
        background: red;  
    }  
}

Das Ergebnis ist auf dem ersten Blick klarer gekapselt und verschafft einen schnelleren Überblick.

Pseudoselektoren & Pseudoelemente

Das Ampersand ist nicht nur auf normale Selektoren beschränkt. Zum Beispiel können wir auch Pseudoklassen verwenden, sollten wir sogar - denn mit Pseudoklassen fängt & erst an Spass zu machen.  Ebenso wie bei CSS Klassen können wir diese Elemente direkt an unsere Basisklasse heften.

a.myClass {  
    background: white;

    &:hover {  
        background: green;  
    }

    &:active{  
        background: red;  
    }

    &:focus {
        outline: 0;
    }  
}

Dies sind natürlich nur ein paar Beispiele und sind beliebig mit allen
anderen CSS Pseudoklassen kombinierbar.

Selbiges geht natürlich auch mit den Pseudoelementen wie ::before und ::after:

.myClass {
    &::before,
    &::after,
    {
        [...]
    }
    &::selection {
        [...]
    }
    &::first-letter {
        [...]
    }
}

Kombinatoren / Combinators

Auch Kombinatoren können mit & verknüpft werden. Da ich ungerne CSS Klassen verschachtele bin ich z.B. ein Freund des > Kombinators. So sieht ein typisches Listenelement bei mir oft so aus:

ul.myList {
    & > li {
        [...]
        & + li {
            [...]
        }
    } 
}

Mit dem CSS Ergebnis:

ul.myList > li {
  position: relative;
}

ul.myList > li + li {
  position: absolute;
}

Wie ich anfangs bereits schrieb, ist das & in diesem Fall komplett optional und wir können dasselbe Ergebnis auch ohne & erreichen.

Siblings & das Double Ampersand

Wo ich schon beim + bin. Wollen wir das nachfolgende Element per CSS ansprechen, ist + sehr hilfreich.

p {
    & + p {
      color: red;
    }
}

Und genau hier hat es mich endgültig getroffen. Das Ampersand ist kein einfaches Element zum Verbinden von CSS Elementen, sondern eine Referenzierung auf das Elternelement - in diesem Fall das p Element. Man kann es also als eine Art Variable sehen, in der die Selektorkette der darüber liegenden Elemente gespeichert wird. Folglich kann man auch folgendes schreiben:

p {
    & + & {
      color: red;
    }
}

Beides führt zum selben Ergebnis:

p + p {
  color: red;
}

Auf diesem Wege kann man ein sauberes SCSS, ohne Wiederholungen, schreiben.

Vorsicht aber bei starker Verschachtelung: Das & bezieht sich auf die ganze Verschachtelung / Selektorkette oberhalb des &. Folgendes Beispiel ...

ul {
  li {
    & + & {
      color: red;
    }
  }  
}

... wird nicht etwa zu ul li + li {...}, sondern zu ul li + ul li {...}.

BEM

Eine echte Zeitersparnis: Wer sein CSS nach BEM benennt, dem wird & besonders gelegen gekommen. In der Tat habe ich das Ampersand sogar erst richtig zu schätzen gelernt, als ich anfing mein SCSS folgendermassen zu notieren:

.block {
  position: relative;
  &__element {
    display: block;
    &--modifier {
      position: absolute;
    }
  }
  &__another-element {
    display: flex;
  }
}

Da & nahtlos verbindet, kann so ein makelloses SCSS Konstrukt erstellt werden. Das CSS hat immer noch eine sehr geringe Spezifizität, aber wir haben trotzdem eine SCSS Verschachtelung was uns hilft das eigene SCSS schneller zu lesen und zu bearbeiten.

.block {
  position: relative;
}

.block__element {
  display: block;
}

.block__element--modifier {
  position: absolute;
}

.block__another-element {
  display: flex;
}

Ausserdem: Entscheiden wir nun später dass .block kein angemessener Name mehr ist, müssen wir es nur an einer einzigen Stelle anpassen und haben damit eine weitere potentielle Fehlerquelle eliminiert.
[3. Eine Anmerkung hierzu: Da der Klassenname in diesem Fall generiert wird, ist es schwieriger im Projekt nach einer SCSS Klasse zu suchen. Ein Problem was aber einfach mit Sourcemaps zu lösen ist. Sollte man zu den unglücklichen Menschen gehören die nicht mit Sourcemaps arbeiten können, einfach nach dem '.block' suchen. Wenn man alles richtig gemacht hat, ist dieser Name unique]

Referenzieren von Elternklassen

Arbeitet man mit Modernizr und seinen generierten Feature-Klassen, kann SCSS so aussehen:

.element {
  display: flex;
  div {
    flex: 1 1 50%;
  }
}
// Fallback
.no-flexbox .element {
  display: block;
  div {
    width: 50%;
  }
}

Wir schreiben ein CSS Modul — und dann schreiben wir es nocheinmal. Nicht wirklich sehr DRY. Besonders bei komplexen CSS Modulen wirkt es so nicht sehr sauber.
Aber wie kann hier & helfen, die Modernizr Klasse .no-flexbox steht ausserhalb des CSS Moduls und bislang haben wir nur ineinander verschachteltes SCSS referenziert?
Bislang hab ich & + * benutzt um Elemente mit nachfolgenden Elemente zu verknüpfen. Danach zeigte ich dass Elemente mit & + & mit sich selbst verknüpft werden können. Da bleibt nur noch eine Variation übrig: * + &.
Setzt man & an das Ende einer CSS Klasse, können in der Hierachie weiter oben liegende Elemente angesprochen werden. In diesem Fall das .no-flexbox.

.element {
  display: flex;
  div {
    flex: 1 1 50%;
  }

  // Fallback
  .no-flexbox & {
    display: block;
    div {
      width: 50%;
    }
  }
}

Wieder bleiben wir in unserer Verschachtelung und erhalten so weiter die Übersicht, da Dopplungen vermieden werden.

Fazit

Das Ampersand ist ein mächtiges SCSS-Werkzeug. Es kann viel Zeit sparen und hat mir persönlich geholfen SCSS noch mehr zu schätzen als ich es ohnehin tat. Wer gerne CSS Komponenten in einer kompakten Schreibweise bündeln möchte, kommt um & nicht herum.
Auch Verschachtelung kann, sofern es richtig eingesetzt wird, zusammen mit & einen echten Mehrwert bieten. Ich mag das Et-Zeichen. Wirklich.

  1. wobei ich dieses nur bedingt als Vorteil empfinde

  2. Zugegeben: Dies ist jetzt eher ein Funfact und noch nicht wirklich sehr spektakulär. Mehr dazu später.