Von Bootstrap zu Susy
#Code

Von Bootstrap zu Susy – Semantische Grid-Systeme mit Sass

Eine (sehr) kurze Geschichte von Grid-Systemen im Webdesign

Ähnlich wie im Printdesign liegt auch der Gestaltung von Websites häufig ein Gestaltungsraster (englisch: Grid) zugrunde. Mit einem Grid wird die zu nutzende Arbeitsfläche in ein einheitliches System aus Zeilen und Spalten gegliedert, welches für Kontinuität in der Gestaltung sorgt.

Das im Jahr 2008 veröffentlichte 960 Grid System gewann schnell an Popularität und markiert den Beginn einer ganzen Flut von CSS-Bibliotheken, die den Aufbau von Gestaltungsrastern im Web vereinfachen sollen.

Die frühen Grid-Systeme waren meist sehr einfach aufgebaut: 12 Spalten mit fix definierten Spaltenbreiten und ebenfalls festgelegten Abständen zwischen den Spalten:

Mit der rasanten Verbreitung von Smartphones und, etwas später, auch Tablets und Phablets, begann der Siegeszug von Responsive Webdesign. Das bedeutet vereinfacht gesagt, dass Websites sich an an die verschiedenen Bildschirmgrößen (bzw. die Größe des Browserfensters) der jeweiligen Geräte flexibel anpassen sollen.

Da sich ein Raster mit fester Breite und konstanter Spaltenanzahl nicht dazu eignet, Inhalt auf Smartphones, Laptops und Widescreen-Displays gleichermaßen gut darzustellen wurden die Grid-Systeme bald fluid. Das heißt, dass Spaltenbreiten nicht mehr in absoluten Werten wie Pixel definiert, sondern mithilfe von prozentualen Angaben festgelegt werden. Je kleiner aber ein Bildschirm ist, desto weniger Spalten lassen sich sinnvoll nebeneinander darstellen. Deshalb legen responsive Grid-Systeme mit Hilfe von Media Queries fest, ab welchen Bildschirmbreite die Unterteilung in Spalten überhaupt erst erfolgen soll. Auf kleineren Bildschirmen werden die ”Spalten” dann linear untereinander dargestellt.

Bootstrap – und was dagegen spricht

Das derzeit wohl am weitesten verbreite Grid-System ist das Bootstrap-Grid. Es ist Teil des Boostrap-Frameworks, welches neben dem Grid-System noch viele weitere UI-Komponenten mit sich bringt.

Das Bootrap-Grid basiert auf dem Grundkonzept, dass im HTML Klassen vergeben werden, die das Layout steuern:

 

<div class="row">
 <div class="col-md-8">Inhalt</div>
 <div class="col-md-4">Seitenleiste</div>
</div>

Hier wird festgelegt, dass ab mittleren Bildschirmbreiten (md) der Inhaltsbereich 8 und die Seitenleiste 4 von 12 Spalten breit sein soll. Die 12 ist hierbei fest vorgegeben, denn Grundlage jedes mit Boostrap aufgebauten Grids ist ein zwölfspaltiges Raster. Das Schema vorgefertigter Klassennamen ist dabei immer folgendermaßen aufgebaut: col-Breakpoint-Spaltenzahl

Diese Klassen lassen sich vielfältig kombinieren. Folgende Anwendung ergänzt unser obiges Beispiel so, dass es auf kleineren Bildschirmen (sm) zu einer Spaltenaufteilung von 6:6 und auf größeren (lg) zu 9:3 kommt.

 

<div class="row">
 <div class="col-sm-6 col-md-8 col-lg-9">Inhalt</div>
 <div class="col-sm-6 col-md-4 col-lg-3">Seitenleiste</div>
</div>

Das funktioniert zwar, ist aber weder schön anzuschauen noch vereinbar mit semantischem HTML und BEM-konformem CSS. Außerdem ist es nicht möglich, Layout-Änderungen vorzunehmen ohne die HTML-Struktur zu verändern.

Fairerweise sei angemerkt, dass auch Bootstrap auf semantische Weise eingesetzt werden kann: bei Verwendung mit Less oder Sass stehen entsprechende Row- und Column-Mixins bereit, die zu benutzen in jedem Fall empfehlenswert ist.

Vorteile semantischer Grid-Systeme

Semantisches Markup bedeutet, dass HTML-Elemente und -Klassen-Namen so gewählt werden, dass sie den Inhalt möglichst gut beschreiben. Das hilft einerseits den Menschen, die den Code schreiben, lesen und überarbeiten enorm, denn sie können ihn schneller verstehen und einordnen. Andererseits hilft semantisches HTML auch Software, von Suchmaschinen bis zu Screenreadern, die die Bedeutung des Inhalts zu erfassen. Das bringt unter Umständen wichtige Vorteile in den Google-Ergebnissen und kann entscheidend zur Barrierefreiheit beitragen. Unser obiges Beispiel könnte folgendermaßen umgeschrieben werden um den Inhalt besser zu repräsentieren:

 

<section class="main">
 <div class="main__content">Inhalt</div>
 <nav class="main__navigation" role="navigation">Seitenleiste</nav>
</section>

Das Ergebnis ist besser lesbar und kann BEM oder einer anderen Konvention folgen, ohne generische Klassennamen zu verwenden. Doch wie wird die gewünschte Spaltenaufteilung erreicht? Moderne Grid-Systeme sind oft ohnehin mit Hilfe eines CSS-Präprozessors aufgebaut, da liegt es nahe, das Spaltenverhalten über Mixins zu regeln. Und genau das machen Sass-basierte Grid-Systeme wie Susy. Die obige Aufteilung von 8:4 wird hier komplett im Sass erreicht, das HTML bleibt also unberührt:

 

.main {
 @include container;
}

.main__content {
 @include span(8 of 12);
}

.main__navigation {
 @include span(4 of 12);
}

Unterschiedliches Verhalten in Abhängigkeit des aktuellen Viewports wird ebenfalls direkt im Sass geregelt, am Besten mit Hilfe eines entsprechenden Mixins für die gewünschten Viewport-Abfragen:

 

.main__content { 
 @include span(6 of 12);

 @include mappy-bp(tablet) {
 @include span(8 of 12);
 }

 @include mappy-bp(desktop) {
 @include span(9 of 12);
 }
}

.main__navigation {
 @include span(6 of 12);

 @include mappy-bp(tablet) {
 @include span(4 of 12);
 }

 @include mappy-bp(desktop) {
 @include span(3 of 12);
 }
}

Auch wenn dies sehr umfangreich erscheint, erweist es sich als sehr nützlich:

  • Die Darstellung wird vom HTML-Markup entkoppelt und kann beliebig im Sass angepasst werden
  • Klassennamen können beliebigen eigenen Konventionen folgen
  • Es können bei Bedarf eigene Breakpoints ergänzt werden, an denen sich das Grid anders verhält

Womit Susy überzeugt

Susy ist als Grid-System sehr flexibel und bietet mehr als nur die konsequente Trennung von CSS und Markup. Einige Highlights aus der Praxis sollen verdeutlichen, wieso die Arbeit mit Susy so effizient ist.

Globale Optionen

Susy berechnet das Grid unter Berücksichtigung der Einstellungen, die in der Sass-Map $susy hinterlegt sind. Hier werden an zentraler Stelle grundlegende Einstellungen wie Spaltenanzahl und Größe des Gutters festgelegt – und können jederzeit geändert werden.

 

$susy: (
 columns: 12,
 gutters: 1/4,
 container-position: center,
 global-box-sizing: border-box,
);

Layout-Switch mit with-layout

Herkömmliche Grid-Systeme stoßen bei augenscheinlich einfachen Aufgaben oft an ihre Grenzen. Folgende Komponente verdeutlicht, wie flexibel Susy dank des with-layout-Mixins is:

Das Problem: beide Komponenten sollen am Grid ausgerichtet sein, die eine jedoch ohne Abstände. Neben der standardmäßig verwendeten Sass-Map $susy können beliebige weitere Sass-Maps mit abweichenden Layouts definiert werden, die die Standardeinstellungen überschreiben. Um das Layout für einzelne Komponenten auf ein vierspaltiges Raster ohne Spaltenabstände umzustellen genügt es, die von $susy abweichenden Werte in ein neues Sass-Map zu schreiben.

 

$teaser-grid: (
 columns: 4,
 gutters: 0
);

Das neue Layout kann dann an beliebiger Stelle aktiviert werden mit:

 

@include with-layout($teaser-grid) {
 // Anweisungen folgen Regeln aus $teaser-grid
}

Nested Grids und Kontext

Verschachtelte Grids in Bootstrap verhalten sich folgendermaßen:

Die Breite der verschachtelten Elemente (Level 2) orientiert sich ihrem jeweiligen Parent (Level 1): drei 3-spaltige Elemente füllen somit nicht die Breite des 9-spaltigen Parent-Elements.

Mit Susy ist es möglich, einem Child-Element einen Kontext mitzuteilen, innerhalb dessen die Spaltenberechnung erfolgen soll.

Den jeweiligen Kontext zu verstehen ist wichtig um effektiv mit Susy zu arbeiten. Wenn das span-Mixin ohne eine of n Angabe verwendet wird geht Susy implizit davon aus, dass es sich um den in $susy definierten Column-Wert handelt. Bei Verwendung eines zwölfspaltigen Rasters impliziert span(8) also span(8 of 12). Das führt bei verschachtelten Grids gern zu Missverständnissen.

In folgendem Layout sind .news__main_first und .news__main_second in .news__main verschachtelt, sollen sich aber auf den Spalten des Parent-Grid anordnen.

 

.news__sidebar {
 @include span(4);
}

.news__main {
 @include span(8 last);
}

.news__main_first {
 @include span(4);
}
 
.news__main_second {
 @include span(4);
}

Ohne einen Kontext-Wechsel verhält sich Susy ähnlich wie Bootstrap: .news__main_first und .news__main_second füllen je ein Drittel ihres Elternelements news__main:

Mit der Ergänzung of 8 kann der Kontext gewechselt werden, die gewünschten 4 Spalten beziehen sich dann auf 8 statt auf 12 Spalten:

 

.news__main_first {
 @include span(4 of 8);
}
 
.news__main_second {
 @include span(4 of 8 last);
}

Das Ergebnis: verschachtelte Elemente lassen sich auf dem Raster ihres Parent-Elements anordnen.

Gutter und Span als Funktion

In Susy handelt es sich bei gutter() und span() nicht nur um Mixins sondern auch um Funktionen. Das heißt, die berechneten relativen Grid-Maße können auch für beliebige CSS-Properties als Wert eingesetzt werden. Ein praktisches Beispiel ist es, vertikale Abstände auf den gleichen Wert des Gutters zu setzen:

 

.foo {
 margin-bottom: gutter(12);
}

Abwärtskompatibilität zu Bootstrap

Aber was ist, wenn eine vorhandene Website an unüberschaubar vielen Stellen im Markup auf Boostrap-Klassen setzt oder vorhandene Extensions diese Klassen ins Markup schreiben? Wer kompatibel zur Boostrap-Nomenklatur bleiben will oder muss kann sich mit die benötigten Klassennamen mit einem Helfer wie Susyboot ins Projekt importieren und weiterhin alle generischen Klassennamen auch innerhalb von Susy benutzen.

Fazit & Ausblick

Die Nützlichkeit und Bedeutung von semantischem Markup und modularem, robustem CSS ist unbestreitbar. Das gilt umso mehr, je komplexer und älter ein Projekt wird. Susy fügt sich wunderbar in einen BEM-orientierten Workflow mit Sass ein und ermöglicht den Aufbau von Layout-Grids in ungeahnter Flexibilität.

Mit der kommenden Version 3 wird Susy ein besseres Plugin-System erhalten, dass es unter anderem ermöglichen soll, die Rendering-Engine auszutauschen und so existierende Layouts beispielsweise von Float- auf Flexbox-Technik oder, in fernerer Zukunft, sogar auf native CSS-Grids umzustellen – ohne dabei ein Refactoring der gesamten Codebase notwendig zu machen.

Weiterführende Links: