senäh

17senäh und so…

CSS Thumbnail

HTML/CSS/JS
16. Apr 2014
Kommentare: 3

Die Geschichte der CSS-Konventionen und mein aktueller Workflow

Kategorien: HTML/CSS/JS | 16. Apr 2014 | Kommentare: 3

Was als gute Praxis in der Webentwicklung angesehen wird, wandelt sich häufig rasant. Teils durch neue Erfahrungen, teils durch neue Technologien. Früher haben wir Webentwickler Styles ins Markup geschrieben – dann wurde CSS erfunden. Nun konnten wir durch Selektoren Teile des DOMs auswählen und mit Styles versehen. Aber je größer die Webseite wurden, umso größer und komplexer wurden die entsprechenden Selektoren, also führte man Namenskonventionen für CSS-Klassen ein, usw. etc. pp. Ihr kennt das Spiel!

Ganz allgemein betrachtet ist die Programmierung immer ein Kampf mit der Komplexität. CSS macht da keine Ausnahme. Dabei ist es nicht immer nur lohnenswert zu erfahren, was ganz aktuell sinnvolle Praktiken sind, sondern auch einen Blick zurück zu werfen, um aus alten Fehlern zu lernen. Und genau das möchte ich heute tun :)

Ein Rückblick – Eine Welt ohne CSS

Je nachdem wie man die Geschichte sehen möchte, begann der erste Veröffentlichung des HTML Standards (damals unter dem Namen “HTML Tags“) 1991. Die Entwicklung des CSS Standards begann 1994, wobei 1996 die erste offizielle Version veröffentlicht wurde. Eine großer Zeitraum also in welchem HTML ohne CSS existierte und die Webwelt noch ganz anders aussah als heute. Ohne CSS musste man damals mittels HTML nicht nur das Markup, sondern auch den Style definieren. Das sah dann damals so aus:

1
<font color="red">Foo</font>

Dadurch haben sich semantische und grafische Elemente vermischt. Außerdem konnten mehreren Elemente so nicht ein und der selbe Style zugewiesen werden – stattdessen musste er pro Element dupliziert werden. Also begann man mit der Entwicklung von CSS, um eine Sprache zu schaffen, welche ausschließlich zur Definition von Styles verantwortlich sein sollte. Im Zuge dessen hat man grafische Elemente (bzw. Attribute) nach CSS überführt (wie color aus dem Beispiel) und anschließend das HTML-Attribut deprecated. So konnte man nicht nur eine spezifische Sprache für Styles schaffen, auch HTML wurde auf diese Weise rückwirkend wirklich Markup-spezifisch.

Das vorige Beispiel sah dank CSS dann so aus:

1
2
3
4
5
<!- HTML -->
<span class="red-font">Foo</span>

/* CSS */
.red-font { color: red; }

Nun konnte man Style-spezifische neue Technologien schaffen zu denen bspw. (CSS-)Klassen gehören. Alles was CSS betrifft, betrifft den Style – alles was HTML betrifft, betrifft Markup. Nur Markup kann semantisch sein, ergo ist CSS immer ohne semantische Bedeutung.

Der Irrtum – HTML ohne CSS

Diese feste Trennung zwischen Markup und Style war extrem hilfreich. Webseiten konnten besser und einfacher entwickelt werden und auch die weitere Standardisierung von HTML und CSS konnte so unabhängig voneinander erfolgen. HTML und CSS zu trennen ist gut – das hatte jeder begriffen. Aber Mitte der 00er Jahre wurde dieser Grundgedanke etwas zu weit getrieben. Es war plötzlich in jegliches CSS aus dem HTML zu entfernen, um dadurch vermeintlich eine noch bessere Trennung und noch bessere Wartbarkeit zu erlangen. So schmiss man sämtliches CSS aus dem HTML heraus – und ich meine nicht nur Inline Styles, sondern auch Klassen.

Neuer Frontend-Code sah häufig so aus:

1
2
3
4
5
<!- HTML -->
<span>Foo</span>

/* CSS */
span { color: red; }

Dieser Frontend-Code ist eindeutig nachteilig. Es ist schwer ohne Klassen eine gewisse Spezifität zu erreichen – schließlich soll nicht jedes span Element einen roten Text haben, sondern nur das span Element im p Element nach dem Logo! Anstatt nun aber zu denken “Mist, wir brauchen doch Klassen!” versuchte man diese Spezifität durch den zuvor genannten Selektorpfad zu erlangen:

1
2
3
4
5
6
<!- HTML -->
<img src="logo.jpg">
<p>Hello <span>Foo</span></p>

/* CSS */
img + p > span { color: red; }

Auch dieser Code ist eigentlich offensichtlich schlecht. Zwar entfernt man das CSS aus dem HTML, aber man holt sich im gleichen Zug HTML-Strukturen ins CSS und bildet Markup mittels Selektoren ab. Was ist außerdem, wenn ich ein weiteres Bild verwenden möchte neben dem Logo? Nun bin ich entweder so clever und baue einen noch größeren Selektor oder ich vergebe eine ID logo, weil IDs natürlich nicht unsemantisch sind – schließlich kann man sie als Anchor nutzen und sind somit Teil von HTML! (Den letzten Part bitte mit einer ironischer Stimme im Kopf lesen.)

1
2
3
4
5
6
<!- HTML -->
<img id="logo" src="logo.jpg">
<p>Hello <span>Foo</span></p>

/* CSS */
#logo + p > span { color: red; }

Die falsche Gegenbewegung – HTML mit semantischen CSS

Über kurz oder lang wurden die Nachteile dieser Arbeit erkennbar. So konnte man CSS-Styles nicht einfach wieder verwenden, da sie zu sehr an die HTML-Struktur gekoppelt waren. Außerdem musste jedes Mal die CSS-Datei angepasst werden, wenn sich das Markup verändert hatte. Daraufhin entwickelte sich eine leider ebenfalls falsche Gegenbewegung, um den Irrtum zu beheben. So zu sagen ein Irr-Irrtum… Diesem Irrtum war ich persönlich leider auch lange aufgesessen. Diese Gegenbewegung hat sich das ursprünglich Problem erneut angeschaut:

1
2
3
4
5
<!- HTML -->
<span class="red-font">Foo</span>

/* CSS */
.red-font { color: red; }

Dabei kam die Gegenbewegung zu dem Entschluss: CSS darf im HTML stehen, wenn es denn semantisch wäre! Der Klassenname .red-font beschreibt das Aussehen, also den Style, und ist deswegen nicht semantisch (- so zumindest die Auffassung der Gegenbewegung).

So sprach man plötzlich von unsemantischen CSS-Klassen, die nichts im Markup verloren hätten. (Auch ich sprach lange Zeit von unsemantischen Klassen…) Die Kritik war folgende:
Klassennamen wie .red-font beschreiben wie etwas aussieht anstatt zu beschreiben was etwas ist. Würde man diese Klassen dementsprechend umbenennen, so entsteht Code wieder dieser:

1
2
3
4
5
<!- HTML -->
<span class="special-text">Foo</span>

/* CSS */
.special-text { color: red; }

Die Gegenbewegung hat eine gute Lösung für die Wartbarkeit von CSS gefunden, verwendet aber die vollkommen falschen Begriffe dafür. Die Idee mit Klassennamen das Was zu beschreiben anstatt das Wie ist sehr viel zukunftsorientierter und weniger fehleranfällig. Wenn jetzt euer Projektmanager entscheidet, dass der .special-text grün sein soll anstatt rot, so müsst ihr dies nur einmal im CSS ändern und der Klassenname bleibt der gleiche. Ansonsten hätte man .red-font in jeder HTML-Datei in .green-font umändern müssen. Oder stellt euch vor ihr seid krank und euer Arbeitskollege traut sich nicht die Klasse umzubenennen, weil er nicht alle HTML-Dateien kennt. Dann habt ihr plötzlich eine Klasse namens .red-font, die grünen Text anzeigt! Verwirrung pur.

Wir halten fest: Die Idee ist gut, aber die Erklärung ist falsch. Der Klassenname .special-text ist genauso unsemantisch wie .red-font, einfach weil jeder CSS-Klassenname unsemantisch ist!

Was sollte man sich aus dieser Erfahrung mitnehmen? Gute CSS-Klassennamen sind solche, die sich möglichst selten ändern! Beim Versuch vermeintlich semantische Klassenamen zu finden, welche das Was anstatt das Wie beschreiben, erhält man häufig sehr gute und sehr langlebige Klassennamen. Diese haben jedoch nichts mit Semantik zu tun. Was man mit semantisch und unsemantisch eigentlich meinte, waren sogenannte presentational classes, also Klassennamen, welche sich auf das Visuelle beziehen anstatt dem Inhalt. Zwar sind inhaltsbezogene Klassennamen häufig sinnvoller, aber präsentationsbezogene Klassenname sind ausdrücklich nicht verboten. Ausschlaggebend ist die Langlebigkeit des Namens.

Es ist interessant wie häufig ich in meiner Entwicklerlaufbahn Blogdiskussionen über die best practices in der Webentwicklung verfolgt habe, nur um am Ende festzustellen, dass die offizielle Spezifikation der jeweiligen Technologie die “beste” best practice vorgibt. So gibt auch dieser Auszug aus dem HTML Spec den eigentlichen Verwendungszweck für CSS-Klassen am besten wieder:

There are no additional restrictions on the [class names] authors can use in the class attribute, but authors are encouraged to use [class names] that describe the nature of the content, rather than [class names] that describe the desired presentation of the content.

Der aktuelle “Trend”

Wir halten kurz fest:

  • Klassen weisen einem Element einen Style zu.
  • Der Klassenname ist lediglich für den Entwickler von Bedeutung – er besitzt keine Semantik oder ähnliches.
  • CSS-Selektoren sollten kein Wissen über das HTML-Markup besitzen.

Damit bleiben wir eigentlich bei diesem Beispiel hängen:

1
2
3
4
5
<!- HTML -->
<span class="special-text">Foo</span>

/* CSS */
.special-text { color: red; }

Was hat sich also verändert? Da wir nun wissen, dass Klassennamen keine Semantik besitzen, müssen wir nicht auf Teufel komm raus nach semantischen (sprich: inhaltsbezogenen) Klassennamen suchen. Wenn es Sinn macht dürfen wir präsentationsbezogene Klassennamen wählen. Dies ist häufig bei Grid Layouts der Fall, welche Klassen wie .row oder .column enthalten, die sich auf keinerlei Inhalt beziehen. Im alten Glauben waren solche Klassennamen verteufelt und man hat nach – teilweise umständlichen, manchmal aber auch sinnvollen – Praktiken gesucht, diese aus dem HTML zu entfernen. Ihre Verwendung ermöglich jedoch eine gewisse Flexibilität, welche für rapid development sehr sinnvoll sein kann. Außerdem sind auf den ersten Blick verständlich – jeder kann sich etwas unter einer .row oder .column vorstellen.

Wir wissen außerdem, dass wir die Klassennamen benennen dürfen wie wir wollen. Wir müssen auf keinerlei Restriktionen achten. Hat man sich an diesen Gedanken gewöhnt, so könnte man sich sogar vorstellen gewisse Meta-Informationen in den Klassennamen zu packen – wenn dies denn sinnvoll ist. Das ermöglicht uns gewisse Namensstandards, womit wir beim nächsten Punkt sind.

Moderne Webseiten sind riesig. Auch wenn CSS nur eine simple Auszeichnungssprache ist, so bedarf es allein wegen ihrer Größe einer guten Architektur, welche eine gute Wartbarkeit, aber auch andere Bedürfnisse wie eine gute Performance erfüllt. Aus diesem Grund haben sich Konzepte wie OOCSSBEM oder SMACSS entwickelt – Frameworks und Konzepte, um CSS sinnvoll zu strukturieren. Diese Konzepte haben natürlich ihrerseits wieder Vor- und Nachteile.

Mein aktueller Workflow

Ich habe mich von OOCSS, BEM und SMACSS, aber auch JavaScript-Frameworks wie AngularJS inspirieren lassen und ein einfaches Regelsystem erstellt, welches ich zurzeit auf der Arbeit erfolgreich verwende. Da sich natürlich auch meine Regeln mit meiner Erfahrung ändern, möchte ich hier gar nicht ins Detail gehen, sondern nur kurz die wichtigsten Punkte nennen:

  • Globaler Prefix: CSS-Klassennamen liegen in einem globalen Scope. Verwende ich zwei unterschiedliche CSS-Frameworks, so laufe ich Gefahr, dass beide die gleichen Klassennamen auf unterschiedliche Art und Weise verwenden. Übel! Das gleiche Problem haben übrigens HTML-Elemente, welche mit Frameworks wie Angular oder auch den zukünftigen Web Components selbst definiert werden können. Hier hat sich die Konventionen eingeschlichen jedes Element mit einem Prefix zu versehen, welches in der Regel zwei Buchstaben lang ist. (Der Web Components Standard setzt übrigens einen Prefix zwingend voraus!) Im Idealfall verwende ich innerhalb des gleichen Frameworks oder Projekts für HTML-Elemente natürlich den gleichen Prefix wie für CSS-Klassen.
    Bsp.: Angular verwendet ng- als Prefix. Wäre ich Hauptverantwortlicher für Bootstrap, so würde ich bs- verwenden.
    Netter Nebeneffekt: Wenn ich mein Projekt nach diesem Prefix durchsuche, finde ich problemlos alle Einsatzorte meiner CSS-Klassen. Ich kann sogar automatisierte Tests über meine Templates laufen lassen, um CSS-Klassen zu finden, welche nicht geprefixt und damit nicht von mir als Entwickler autorisiert sind und ggf. vom Praktikanten eingesetzt wurden…
  • Modulprefix: Ich versuche meine CSS-Dateien in möglichst einzelnen und in sich logischen Modulen zu verwalten, welche ich dann z.B. mittels Bower verteilen kann. Auf diese Weise weiß ich sofort beim Einsatz einer Klasse aus welchem Modul sie stammt.
    Bsp.: Anstatt Buttons, Formulare und Co. in einem Projekt zu pflegen, teile ich sie in unterschiedliche Bower Packages auf. Anstatt .row und .column heißen meine Klassen .my-grid-row und .my-grid-column. Ich weiß sofort, dass beide Klassen auf dem grid Modul stammen und nicht aus dem table Modul. (my wäre in diesem Beispiel der globale Prefix.)
  • Modifier: Wenn ich eine leichte Variation eines bestimmten Elementes haben möchte, so verwende ich einen Modifier mit einem mod- Kürzel.
    Bsp.: .my-button.my-button-mod-primary und .my-button.my-button-mod-secondary.
  • Angular: Was hat Angular hier zu suchen? Es soll exemplarisch für die Koppelung zwischen CSS, HTML und JavaScript stehen, welche manchmal nicht vermeidbar ist. Manche Entwickler führen als zusätzliche Konvention noch den js- Prefix ein, welcher zeigt, dass eine CSS-Klasse ebenfalls bzw. ausschließlich von JavaScript aus verwendet wird. Diese Regel empfehle ich auch, aber im Idealfall setze ich ein Framework wie Angular ein und style selbst geschriebene Elemente bzw. Attribute mittels CSS. Wenn ich also ein Element namens <my-button> style, dann weiß ich sofort, dass sich dahinter ein JavaScript-Datei verbirgt. Diese Elemente zeichnen sich u.a. dadurch aus, dass sie dynamisch ihren Status ändern können, welche durch Attribut-Selektoren gestylt werden können. So kann ein Button bspw. aktiviert oder deaktiviert sein: <my-button disabled>.
    Achtung: In der Regel sind Attribut-Selektoren langsamer als CSS-Klassenselektoren, aber das sollte in den wenigsten Fällen ein echtes Problem sein. Wenn doch, dann benutzt ihr eben eine weitere Konvention wie den bereits erwähnten js- Prefix.
  • Weitere Best Practices: ID-Selektoren vermeiden, !important vermeiden, komplexe Kind- und Nachfolgeselektoren vermeiden (Inception-Regel), containeragnostisch arbeiten (jedes Element sollte immer gleich aussehen, egal in welchem Container es liegt) und die Spezifität über die Reihenfolge von Styles gewinnen anstatt durch komplexere Selektoren (es heißt schließich Cascading Style Sheets…).

Ich hoffe, ihr konntet den ein oder anderen nützlichen Hinweis mitnehmen. :) Wenn ihr Fragen habt, dann schreibt einfach einen Kommentar.

Viele Grüße,
Pipo :)

Autor: Pipo

...kommt ursprünglich aus der Designerecke, ist aber im Laufe seines Studiums in die Webentwicklung gestolpert. Kann sich seit dem nicht so richtig entscheiden wo er hingehört und wagt deswegen vielleicht die Flucht nach vorne in ein komplett neues Gebiet. Vielleicht Management? Niemand weiß es. Auch er nicht.

Kommentare (3)

  1. Super Artikel, sehr Hilfreich und gut erklärt, vielen Dank vorallem für den Teil mit dem Workflow! Ich schätze jetzt habe ich zwei Probleme weniger, so kann ich eine wirklich gute Struktur entwickeln und zeit sparen.

    ich habe mir meinen Workflow jetzt angepasst, eigentlich fast komplett diesen hier übernommen und hoffe das ich nun schneller werde und meine Gründlichkeit beibehalten kann.

    Gruß!
    Benjamin

  2. Das war mal nötig, das zusammenzufassen. Als einer, der die “Semantic HTML/CSS”-Kriege ;) noch mitgefochten hat, bin ich froh, dass wieder Pragmatismus einkehrt.