Bei der Arbeit an großen, langlebigen Projekten mit vielen Entwicklern unterschiedlicher Spezialisierungen und Fähigkeiten ist es wichtig, dass alle einheitlich arbeiten, um Stylesheets sowohl pflegbar als auch skalierbar zu halten und um zu gewährleisten, dass der Code transparent und lesbar bleibt.
Aus diesem Antrieb heraus entstand dieser Styleguide, der es Entwicklern ermöglichen soll, die Code-Qualität hochzuhalten, die Code-Konsistenz zu wahren und produktiver zu arbeiten.
ZASAF folgt dem Grundgedanken von BEM und SMACSS, dass Frontends modular aufgebaut werden sollten. Dabei unterscheiden wir jedoch noch einmal zwischen generischen und spezifischen Komponenten. Wir organisieren unseren Stylesheet-Ordner wie folgt:
- generic-components
- specific-components
- abstract-components
- globals
- utilities
Als generisch ordnen wir die Komponenten ein, die ihrer Natur nach wiederverwendbar sind.
.button
, .data-table
, .fact-list
, horizontal-form
- Konsistenz des UIs
- Effiziente Zusammenstellung neuer UIs durch Wiederverwendung
- Alle Instanzen einer Komponente können zentral angepasst werden
- beschreibt die Funktion, nicht den Inhalt
- ist i.d.R. nicht spezifisch für die Anwendung
- ist ein Nomen, ggf. mit Adjektiv davor
Frontend-Komponenten, die für einen bestimmen Anwendungsfall geschaffen werden und nicht zur allgemeinen Verwendung gedacht sind, kennzeichnen wir als spezifische Komponenten.
.company-search
, .product-page
, .about-us-illustration
- simpler zu schreiben, da nicht auf Wiederverwendung ausgelegt
- simpler zu warten, da es nur eine Instanz der Komponente geben kann
- darf spezifische Details wie Layoutinformationen enthalten
- beschreibt eindeutig einen konkreten Inhalt
- ist i.d.R. spezifisch für die Anwendung
- ist ein Nomen, ggf. mit Adjektiv davor
Immer dann, wenn sich mehrere Komponenten Aussehen oder Verhalten teilen, extrahieren wir den Sass-Code und machen daraus eine abstrakte Komponente. Der Unterschied zu den generischen und spezifischen Komponenten liegt darin, dass abstrakte Komponenten keinen Klassennamen bekommen sondern lediglich als Mixin existieren.
=boundary-box($padding: true)
width: 100%
max-width: $layout-width
margin: 0 auto
@if $padding == true
+respond-to(large)
padding: 0 $space-l
+respond-to(medium)
padding: 0 $space-m
+respond-to(small)
padding: 0 $space-s
- DRY
- besser zu warten, da der Code zentral angepasst werden kann
- Konsistenz des UIs
- beschreibt eindeutig einen konkreten Inhalt oder eine konkrete Funktion
- ist i.d.R. nicht spezifisch für die Anwendung
- ist ein Nomen, ggf. mit Adjektiv davor
Varianten und Status einer Komponente werden mit Modifier abgebildet. Sie treten immer nur in direkter Verbindung mit einer Komponente auf.
.button.is-primary
,.text-link.is-unobtrusive
,.product-list--entry.is-sold-out
,.button.primary.is-disabled
,.navigation.has-submenu
,.button.has-addon
- beschreibt einen Zustand oder besonderes Verhalten einer Komponenteninstanz, wodurch eine Variante entsteht
- wenn sich der Modifier auf den Zustand oder das Verhalten einer Komponenteninstanz bezieht, benutzt man das
is
-Prefix und ein einfaches Adjektiv - falls eine Komponenteninstanz sich auf einen Bestandteil der Komponenteninstanz bezieht, benutzt man das
has
-Prefix und ein einfaches Nomen - die Prefixe werden benötigt, damit ein Modifier einfach identifiziert werden kann und Zustände abgebildet werden können, für die Adjektive nicht ausreichend sind
- steht nie alleine, sondern ist nur in Verbindung mit der Komponente eindeutig (Warum?)
Die Unterscheidung von generischen und spezifischen Komponenten ist der wichtigste Unterschied zu BEM. Die anderen Konzepte verwenden wir mit der gleichen Semantik wie BEM.
- Block in BEM = generische oder spezifische Komponente in ZASAF
- Element eines Blocks in BEM = Element einer Komponente in ZASAF
- Modifier eines Blocks in BEM = Modifier einer Komponente in ZASAF
Die Syntax von BEM finden wir jedoch etwas sperrig und haben uns für ein anderes Namensschema entschieden:
BEM | ZASAF |
---|---|
%ul.fact-list
%li.fact-list__entry
%li.fact-list__entry.fact-list__entry--highlighted
|
%ul.fact-list
%li.fact-list--entry
%li.fact-list--entry.is-highlighted
|
.fact-list
list-style-type: disc
.fact-list__entry
line-height: 1.2
.fact-list__entry--highlighted
font-weight: 700
|
.fact-list
list-style-type: disc
.fact-list--entry
line-height: 1.2
&.is-highlighted
font-weight: 700
|
- Der Komponenten-Namensraum wird also mit
--
vom Elementnamen abgegrenzt. - Modifier kommen ohne Namensraum aus, da sie ausschließlich in Kombination mit einer Komponente bzw. einem Element eingesetzt werden.
.product
%aside.product--images
%ul.media-list
%li.media-list--item
%img.media-list--image{…}
%li.media-list--item
%img.media-list--image{…}
.product--information
%h1.headline.xl Musterprodukt
.headline
+font-serif
&.xl
+text-copy(xl)
.media-list
margin-bottom: 20px
.media-list--item
width: 100%
.media-list--image
display: block
.product
background-color: $color-product-background
.product--images
+column(4)
.product--information
+column(8)
Im Order globals
befinden sich globale Basisstile und Konfigurationen:
- _base.css.sass: Styling der HTML-Elemente (z.B.
strong {font-weight: 700}
) - _colors.css.sass: Farbdeklarationen (z.B.
$color-accent: $curious-blue
) - _reset.css.sass: Standard-Reset der HTML-Elemente (z.B.
ol, ul {list-style: none}
} - _typography.css.sass: Font-Stack-Deklarationen und Text-Mixins (z.B.
@mixin font-serif {font-family: $font-stack-serif}
- …
Im Ordner utilities
befinden sich Mixins, die in Komponenten eingesetzt werden können:
- _clearfix.css.sass
- _font-smoothing.css.sass
- _grid.css.sass
- _responsify.css.sass
- …