search home list

Sass mit Vorsicht: @extend

Die mit dritten Version von Sass eingeführte @extend Funktion, ist für Designer und Entwickler ein effizientes Tool, um ihren Sass-Code möglichst DRY zu halten. Der richtige Einsatz von @extend optimiert den Code und schützt vor übermäßiger Verwendung von semantisch schwachen CSS-Klassen in der HTML-Struktur. Die Wartung des Codes wird somit vereinfacht und erspart Designern und Entwicklern viel Kopfschmerz. Doch das Leben ist kein Ponyhof und wie die meisten Sass-Funktionen ist auch @extend mit Vorsicht zu genießen.

Verschachtelte @extend Anweisungen führen zu schlechtem CSS-Code

Im Laufe des letzten Projekts hier bei intuio, ist uns aufgefallen, dass der durch @extend kompilierte CSS-Code äußerst chaotisch und dadurch problematisch sein kann. Dieses Problem tritt dann auf, wenn @extend Anweisungen in verschachtelten Selektoren auftreten. Sehen wir uns dazu ein Beispiel an: der folgende Code zeigt eine stark vereinfachte Variante eines Navigationsmenüs, mit zwei unterschiedlichen farblichen Ausprägungen.

HTML-Code


<!-- Eine simple Navigation -->
<ul class="nav">
<li class="nav__item">Products</li>
<li class="nav__active-item">Images</li>
<li class="nav__item">Press</li>
</ul><!-- Eine alternative Variante der simplen Navigation -->
<ul class="nav--alt">
<li class="nav--alt__item">Different Products</li>
<li class="nav--alt__active-item">And different Images</li>
<li class="nav--alt__item">And a different Press</li>
</ul>

Verschachtelter SCSS-Code

Beide Navigationsmenüs sollen horizontal verlaufen, jedoch soll die alternative Variante eine andere Highlight-Farbe haben. Hier der entsprechende SCSS-Code dazu.


.nav
{
margin:0;
padding:0;font-family:sans-serif;
font-size:24px;

.nav__item
{
display:inline-block;
margin-right:20px;


&:last-child
{
margin-right:0;
}
}

.nav__active-item
{
@extend .nav__item;
font-weight:700;
color:#10ADED;
}
}

.nav--alt
{
@extend .nav;

.nav--alt__item
{
@extend .nav__item;
}

.nav--alt__active-item
{
@extend .nav__active-item;
color:#BADA55;
}
}

Dieser Code scheint auf den ersten Blick nicht problematisch zu sein. Es gibt die grundlegenden Stilanweisungen für die Standardvariante der Navigation und die entsprechenden @extend Aufrufe zur Vererbung der Stile an die Variation. Unterschiedliche Stile werden dann einfach überschrieben. Das Problem dabei ist jedoch der CSS-Code, den der Compiler ausspuckt, denn dieser sieht so aus:

CSS-Code


.nav,
.nav--alt
{
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 24px;
}

.nav .nav__item,
.nav--alt .nav__item,
.nav .nav__active-item,
.nav--alt .nav__active-item,
.nav .nav--alt .nav--alt__active-item,
.nav .nav--alt .nav--alt__active-item,
.nav--alt .nav .nav--alt__active-item,
.nav--alt .nav .nav--alt__active-item,
.nav .nav--alt .nav--alt__active-item,
.nav--alt .nav .nav--alt__active-item,
.nav--alt .nav--alt__active-item,
.nav .nav--alt .nav--alt__item,
.nav--alt .nav .nav--alt__item,
.nav--alt .nav--alt__item
{
display: inline-block;
margin-right: 20px;
}

.nav .nav__item:last-child,
.nav--alt .nav__item:last-child,
.nav .nav__active-item:last-child,
.nav--alt .nav__active-item:last-child,
.nav .nav--alt .nav--alt__active-item:last-child,
.nav .nav--alt .nav--alt__active-item:last-child,
.nav--alt .nav .nav--alt__active-item:last-child,
.nav--alt .nav .nav--alt__active-item:last-child,
.nav .nav--alt .nav--alt__active-item:last-child,
.nav--alt .nav .nav--alt__active-item:last-child,
.nav--alt .nav--alt__active-item:last-child,
.nav .nav--alt .nav--alt__item:last-child,
.nav--alt .nav .nav--alt__item:last-child,
.nav--alt .nav--alt__item:last-child
{
margin-right: 0;
}

.nav .nav__active-item,
.nav--alt .nav__active-item,
.nav .nav--alt .nav--alt__active-item,
.nav--alt .nav .nav--alt__active-item,
.nav--alt .nav--alt__active-item
{
font-weight: 700;
color: #10ADED;
}

.nav--alt .nav--alt__active-item
{
color: #BADA55;
}

Wie man deutlich erkennen kann, erzeugt diese Methode extrem viel Overhead für ein eigentlich sehr simples Ergebnis. Jeder der ein wenig CSS-Erfahrung hat weiß, dass dieses Ergebnis mit sehr viel weniger Code erreicht werden kann und objektiv gesehen ergeben sich daraus folgende Probleme:

Sehen wir uns im Gegensatz dazu eine optimierte Version ohne Verschachteln der @extend Funktion an.

Unverschachtelter SCSS-Code


.nav
{
margin:0;
padding:0;font-family:sans-serif;
font-size:24px;
}

.nav__item
{
display:inline-block;
margin-right:20px;

&:last-child
{
margin-right:0;
}
}

.nav__active-item
{
@extend .nav__item;
font-weight:700;
color:#10ADED;
}

.nav--alt
{
@extend .nav;
}

.nav--alt__item
{
@extend .nav__item;
}

.nav--alt__active-item
{
@extend .nav__active-item;
color:#BADA55;
}

Dieser optimierte SCSS-Code veranlasst den Compiler dazu, folgenden CSS-Code zu generieren:

CSS-Code


.nav,
.nav--alt
{
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 24px;
}.nav__item,
.nav__active-item,
.nav--alt__active-item,
.nav--alt__item
{
display: inline-block;
margin-right: 20px;
}

.nav__item:last-child,
.nav__active-item:last-child,
.nav--alt__active-item:last-child,
.nav--alt__item:last-child
{
margin-right: 0;
}

.nav__active-item,
.nav--alt__active-item
{
font-weight: 700;
color: #10ADED;
}

.nav--alt__active-item
{
color: #BADA55;
}

Dieser Code ist 3x kleiner, als der aus dem Verschachteln heraus generierte Code und erzielt trotzdem dasselbe simple Ergebnis.

Fazit

Man sollte bei der Nutzung von Sass generell versuchen, Verschachteln von Selektoren zu vermeiden. Grundsätzlich ist es ok, in speziellen Fällen bis zu 3x mal tief zu schachteln, doch sollte man stets das generierte CSS überprüfen und nach möglichen Optimierungen suchen. Manchmal ist es tatsächlich notwendig, Selektoren zu schachteln und ihre Reichweite einzuschränken, aber häufig findet sich bei genauerem Hinsehen eine alternative Implementierung, die das Verschachteln überflüssig macht. So gibt es zum Beispiel Naming Conventions für Selektoren, die Abhilfe schaffen. Wir haben mit BEM recht gute Erfahrungen gemacht.

Weiterführende Artikel

Show all articles

What do you think?