CSS ist einfach zu schreiben, aber schwierig zu warten. Vor allem nach längerer Projektabwesenheit oder beim Arbeiten im Team. Eine Methode, um Code schlank und übersichtlich zu halten ist eine Herangehensweise mit multiplen modularen classes. Wie Lego Bausteine kann man dadurch seine Styles wiederverwenden und verschieden kombinieren. Eine Herangehensweise in drei Schritten.
1. Classes statt HTML-Elemente selektieren
Der erste Schritt CSS so zu gestalten, dass es sich wie Lego Bausteine verhalten kann, ist es so unabhängig wie möglich vom Umfeld, also den HTML-Elementen und der Struktur im Markup zu machen. Praktisch bedeutet das classes als Selektoren gegenüber Element-Selektoren zu bevorzugen.
Früher habe ich genau das Gegenteil davon gemacht und sehr komplexe und verschachtelte Element-Selektoren geschrieben. Höchstens für Container habe ich classes vergeben, doch für Einzelelemente fast nie. Ich wollte möglichst wenig classes verwenden, da ich es für unnötig empfand. Ich war fest davon überzeugt, dass sich die Struktur des Markups nicht ändern würde. Wenn ich z.B. in der Sidebar einen Link in einer Promo-Box als Button gestalten wollte, hat das ganze so ausgehen:
.sidebar > div > a {
/* Mein Button-Styling */
}
Das war eine klassische Situation, in der das Styling komplett von der HTML-Struktur abhängig ist (davon abgesehen, dass ich so jeden Link innerhalb der Box in der Sidebar selektiere, was ich wahrscheinlich gar nicht möchte). Wenn ich nun ein weiteres div
ergänze, eines wegnehmen oder den Button auch im Footer einsetzen möchte, muss ich nicht nur mein HTML sondern auch das CSS umschreiben. Viel einfacher ist es hier eine class zu vergeben und diese zu selektieren:
<a class="btn" href="#">Button</a>
.btn {
/* Styling für einen Button */
}
Auf diese Weise kann ich meine classes unabhängig von der Markup-Struktur einsetzen. Ich kann den Button aus einem Container herausnehmen, in einem anderen einsetzen und erhalte das gleiche Ergebnis. Er gestaltet sich nicht aufgrund seines Umfeldes. Diesen Mehrwert habe ich damals nicht erkannt. Ich wollte mein Markup möglichst unabhängig von classes halten, erzeugte dadurch aber nur die Notwendigkeit mein CSS von der HTML-Struktur anhängig zu machen. Dabei habe ich mich auf fixe Struktur verlassen. Doch Strukturen ändern sich und ich bin lieber darauf vorbereitet. Denn einem HTML-Element eine andere class zuzuweisen ist meistens schneller als mein CSS strukturell zu überarbeiten. Und es ist auf jeden Fall leichter nachvollziehbar und verständlicher.
2. Classes wiederverwendbar schreiben
Das tolle an Lego Steinen ist, dass man sie immer wieder verwenden kann und auch seinen Code sollte man in verschiedenen Situationen möglichst wieder verwenden können. Sehen wir uns ein Beispiel für das Stylen von Überschriften an. So eine Art Stylesheet wird vielen vertraut vorkommen:
h1 {
/* Styling für h1 */
}
h2 {
/* Styling für h2 */
}
h3 {
/* Styling für h3 */
}
Das Styling der Überschriften ist an die HTML-Elemente gebunden und lässt sich so nicht auf andere Stelle übertragen. Das zwingt einen dazu die jeweiligen Headings dem gewünschten Styling nach zuzuweisen (was semantisch wie Suchmaschinentechnisch wenig wünschenswert ist) oder oder man endet mit solchen Selektoren, um mit Abweichungen umzugehen:
h1,
.section-header h3,
.section-teaser h2,
.promobox-title {
/* Styling für h1 /*
}
Wesentlich nachhaltiger und einfacher ist es auch hier classes zu schreiben:
.alpha {
/* Styling für h1 */
}
.beta {
/* Styling für h2 */
}
.gamma {
/* Styling für h3 */
}
<h3 class="alpha">Style von Überschrift 1 in einer h3</h3>
<p class="gamma">Style von Überschrift 3 in einem paragraph</p>
Dieser Herangehensweise erfordert zwar, dass ich jeder Überschrift eine class zuweise, doch das ist in Summe leichter verständlich und wartbarer, als komplexe CSS-Selektoren zu schreiben, zu verändern und zu erweitern.
3. Classes modular schreiben
Um die Wiederverwendbarkeit von classes wirklich zu gewährleisten, sollte man classes so schreiben, dass sie unterschiedlich miteinander kombiniert werden können. Ganz so wie verschiedene Lego Bausteine, die ein neues Ganze ergeben. Das erreicht man, wenn man Struktur und Aussehen möglichst trennt, also modular macht. Und das nach dem Motto des „Single Responsibility Principle“: ein Ding kann eine Sache, aber die wirklich gut. Führen wir unser Button-Beispiel von vorher etwas weiter aus. Wahrscheinlich werde ich mehrere Arten von Buttons auf meiner Seite verwenden, z.B.:
- Standard-Button als allgemeiner Stil
- Primär-Button für besondere Aufrufe
- Sekundär-Button der sich eher zurücknimmt
- Disabled-Button der zeigt, wenn etwas nicht klickbar ist
Diese Buttons könnte es dann auch noch in verschiedenen Größen geben:
- Normaler Button
- Kleiner Button
- Großer Button
Jetzt könnten wir für all diese Buttons einzelne classes definieren, wie z.B.:
.btn--default {}
.btn--default--big {}
.btn--default--small {}
.btn--primary {}
.btn--primary--big {}
.btn--primary--small {}
.btn--secondary {}
.btn--secondary--big {}
.btn--secondary--small {}
.btn--disabled {}
.btn--disabled--big {}
.btn--disabled--small {}
Das bedeutet aber, wir hätten nun zwölf verschiedene classes zu warten. Und auch zwölfmal das Grund-Styling für unseren Button zu definieren und zu wiederholen, was nicht besonders dry ist. Müssen wir z.B. die generelle Gestaltung des kleinen Buttons anpassen, dann müssen wir das vier mal machen – für den normalen, den primären, sekundären und disabled Button. Das wird in der Wartung ziemlich schwierig und unübersichtlich. Der modulare Ansatz dazu ist folgenderweise:
.btn {
/* Grundeinstellungen aller Buttons */
display: inline-block;
text-decoration: none;
font-family: sans-serif;
padding: 1em 2em;
…
}
.btn--default {
/* Stilistische Einstellungen des Standard-Buttons */
background-color: blue;
color: white;
…
}
.btn--primary {
/* Stilistische Einstellungen des Primär-Buttons */
background-color: red;
color: white;
…
}
.btn--secondary {
/* Stilistische Einstellungen des Sekundär-Buttons */
border: 2px solid blue;
background-color: white;
color: blue;
…
}
.btn--disabled {
/* Stilistische Einstellungen des Disabled-Buttons */
background-color: lightgray;
color: gray;
…
}
.btn--big {
/* Stilistische Abweichungen des großen Buttons */
font-size: 1.5em;
padding: 1.2em 2em;
…
}
.btn--small {
/* Stilistische Abweichungen des kleinen Buttons */
font-size: 0.8em;
padding: 0.5em 1em;
…
}
<a href="#" class="btn btn--default">
Standard Button
</a>
<a href="#" class="btn btn--primary btn--big">
Primary Button Groß
</a>
<a href="#" class="btn btn--secondary btn--small">
Sekundärer Button klein
</a>
<a href="#" class="btn btn--disabled">
Disabled Button
</a>
In Summe sind es nur sieben classes mit denen man theoretisch zwölf Varianten darstellen kann, je nachdem, wie man sie kombiniert. Dabei sind die Aufgaben der verschiedenen classes möglichst getrennt. Das Basis-Styling übernimmt .btn
mit dem generellen Einstellungen, die sich über alle Varianten zieht (wie padding, margin, Schrift, display-Eigenschaften). Es ist praktische der erste Lego Stein, der allen Buttons zugrunde liegt.
Darauf folgen verschiedene Steine, die das funktionale Styling übernehmen. Das sind die classes .btn--default
, .btn--primary
, .btn--secondary
und .btn--disabled
mit verschiedenen Farben und Hintergrundfarben. Ein Button braucht so mindestens zwei classes. Um mit Abweichungen umzugehen, gibt es eine dritte Art von Steine. .btn--big
und .btn--small
definieren die Veränderungen in den Größen vom Standard, der von .btn
definiert ist. Demnach müssen sie auch als letzte zugewiesen werden.
Möchte ich z.B. nun die Abmessungen der kleinen Buttons oder die Farbe der Disabled Buttons anpassen, muss ich dafür nun jeweils eine Änderung vornehmen. Das ist nachvollziehbar und schnell erledigt. Außerdem beeinflusse ich damit nicht die all Buttons überschneidenden Regeln. Möchte ich, das ein spezieller Button auf meiner Seite anders aussieht, kann ich das im HTML ergänzen. Ich habe auf CodePen eine Demo geschrieben, bei der man das gleich selbst ausprobieren kann.
See the Pen CSS buttons as Modular Multiple Class approach by Oliver (@glyphe) on CodePen.
Zusammengefasst
Früher verfiel auch ich dem Wunsch möglichst keine bis wenige classes in mein Markup zu schreiben. Diese Herangehensweise hat in vielen Fällen zu unübersichtlichem, schwer erweiterbarem und wartbaren Code geführt. Deshalb habe ich nach einem anderen Umgang mit meinen Selektoren gesucht. Durch die Herangehensweise mit multiplen modularen classes erreicht man:
- Unabhängigkeit von der Markup-Sturktur – ich kann meine Styles an beliebigen Stellen der Seite einsetzen und von einer Stelle auf eine andere nur mit einer Änderung im HTML übertragen.
- Nachvollziehbarkeit wie das Design auf einzelne Elemente zugreift und dadurch mehr Sicherheit beim Arbeiten im Team oder wenn man nach längerer Zeit zu einem Projekt wieder zurückkehrt.
- Natürlich auch mehr Markup. Doch der Aufwand dieses zu erweitern bzw. zu verändern ist meistens geringer, als CSS um eine komplexe Selektor-Sturktur zu erweitern oder zu verändern.
Abschließend möchte ich noch betonen, das viele der Dinge, die ich hier schreibe nicht neu sind. Sie waren es nur für mich und sind wahrscheinlich eine Zusammenfassung einiger Beiträge von Harry Roberts. Diese Herangehensweise von objektorientiertem CSS (OOCSS) ist auch bei den wunderbaren CSS Guidelines zu finden.
Leave a Reply