CSS Kurs Teil 1

Teil 1:
Wie ihr CSS-Klassen richtig in Contao benennt

So nutzt ihr die richtigen Namen in Contao

Im ersten Teil unserer Artikelserie CSS-Kurs für Contao beschäftigen wir uns mit Namen für CSS-Klassen. Zu oft vergessen wir, dass eine gute CSS-Schreibweise bereits bei der richtigen Benennung von Klassen anfängt.

Ich denke mal 8 von 10 Entwicklern stimmen mir zu, wenn ich sage, dass die richtige Benennung von CSS-Klassen zu einer der größten Herausforderungen beim Schreiben von CSS gehört. An Kreativität mangelt es dabei nicht, sondern es geht schlichtweg darum, dass wir nicht absehen können, wie sich eine Website entwickelt. Sei es in einem Jahr oder im Verlaufe der Umsetzung.

In diesem Artikel möchte ich 4 Fragen nachgehen:

Das Problem: die richtige Bezeichnung von Klassen

Als ich mich mich vor ca. 10 Jahren das erste Mal mit HTML und CSS beschäftigte, war ich schon froh, wenn es einfach nur funktionierte. Webdesign steckte in den Kinderschuhen und Browser-Unterstützung und IE-Hacks waren schon Herausforderung genug.

Es hat Jahre gedauert, bis ich CSS nicht einfach nur so runtergeschrieben habe, sondern damit begann, mir ernsthafte Gedanken über Effizienz bei der Umsetzung zu machen und wie meine CSS-Anweisungen strukturiert sein sollten, damit ich mich später darin wieder zurechtfinde. Dass ich eben nicht ein Design von oben nach unten und von vorne nach hinten umsetzte. Und dass ich nicht bei jeder Seite, in der sich Teile des Layouts wiederholten, einfach die CSS-Anweisungen kopierte und für meine neue Klasse einfügte.

Aber wie bezeichnet man eine Klasse am Besten, sodass man sie seitenübergreifend und auch morgen, in einem Monat oder in einem Jahr wiederverwenden kann?

Ein Beispiel: Für ein kleines Projekt haben wir für unseren Kunden einen One-Pager gebastelt. Ziel ist es, dass der Nutzer auf der Seite das Formular ausfüllt. Den Button im Formular haben wir .btn-submit genannt.

.btn-submit {
    background: red;
    border-radius: 3px;
    border: 0;
    color: white;
    […]
}

Dadurch, dass auf der Seite nur ein Button vorkommt, ist der Klassenname eigentlich perfekt. Auch für eine Newsletter-Anmeldung, die einen Monat später integriert werden soll, passt sie ausgezeichnet. Dann aber soll der gleiche Button ein halbes Jahr später für einen Dateidownload genutzt werden und an anderer Stelle als Call-to-Action-Button „Jetzt anmelden“. Spätestens jetzt trifft der Begriff submit nicht mehr die eigentliche Aufgabe des Buttons.

Nun gibt es drei Möglichkeiten:

  • man benennt die Klasse im Zuge eines CSS-Refactoring um (bei einer kleinen Website bzw. einem One-Pager nicht das Problem)
  • man verständigt sich darauf, die Klasse eben auch zu nutzen, wenn man eigentlich gar nichts submitted absendet.
  • man kopiert sich die CSS-Anweisungen von .btn-submit für seine neue Klassen .btn-cta und .btn-download

Theoretisch könnte man auch darüber nachdenken, die beiden Klassen einfach per Komma getrennt an die bestehende Klasse .btn-submit anzuhängen. Daran denken aber in so einer Situation die Wenigsten. Oder es führt mitunter dazu, dass die Klasse irgendwo in einem Bereich, in dem sonst nur Anweisungen für das Formular stehen, verkümmern.

Die beiden letzteren Möglichkeiten – die „falsche“ Bezeichnung dennoch zu verwenden oder die zwei neuen Anweisungen mit identischem Inhalt anzulegen – sind zwar die einfachsten Lösungen, aber für unsere CSS und die spätere Verwaltung der Website auch die Schlechtesten. Sie machen ein Projekt unübersichtlicher und die CSS-Datei(en) werden unnötig „aufgeblasen“. Hinzu kommt, dass wir im Falle von Änderungen am Button durch alle Klassen durchgehen müssen, um die Änderungen durchzuführen (wenn wir nicht gerade mit einem Präprozessor wie LESS oder SASS arbeiten und Mixins nutzen).

Die Frage ist also, wie kann man mit der richtigen Benennung solchen Situationen vorbeugen?

Schiff grau

1. Die unterschiedlichen Klassennamen-Typen

Wenn wir uns neue Klassenbezeichnungen überlegen, dann lassen sich diese in den meisten Fällen einer dieser 3 Typen zuordnen:

  • beschreibende Klassennamen
  • kontextbezogene Klassennamen
  • funktionelle Klassennamen

Schauen wir uns die 3 Typen einmal genauer an:

Kontextbezogene Klassennamen

Der weiter oben erwähnte .btn-submit ist ein gutes Beispiel für einen kontextbezogenen Klassennamen. Der Name beschreibt, das er zum Absenden – vermutlich eines Formulars – genutzt wird.

Der Vorteil: selbst ein neuer Entwickler, der in ein bestehendes Projekt kommt, weiß nach spätestens 2 Minuten, dass diese Klasse dem Absenden-Button im Kontaktformular sein Aussehen gibt.

Der Nachteil: Die Klasse lässt sich nur mit Einschränkungen auch auf andere Buttons anwenden. Für Formulare, in denen etwas abgeschickt wird, ist er super, für einen hervorgehobenen Link, der wie ein Button aussieht ist er allerdings nicht geeignet.

Ein weiteres Beispiel: die Klassen .mainnav und .footernav. So oder so ähnlich haben wir in vielen Projekten unsere Hauptnavigation und Footernavigation gestylt. Dabei könnte man die Gestaltung  – eine ungeordnete Liste ohne list-style-type und mit gefloateten Listenelementen – auch durchaus noch an anderer Stelle verwenden. Nur wäre dann die Bezeichnungen vermutlich nicht so intuitiv.

Beschreibende Klassennamen

Bleiben wir noch mal bei dem Beispiel mit dem Absenden-Button. Wenn wir unseren roten Button auch außerhalb des Formulars und ohne Kontext nutzen wollen, drängt sich der Gedanke förmlich auf, die Klasse einfach nach ihrer Gestaltung zu benennen, also .btn-red.

Der Vorteil: Auch hier findet sich ein neuer Entwickler oder wir uns nach 1-2 Jahren sofort zurecht. Außerdem lässt sich der Button jetzt an nahezu beliebiger Stelle auf der Website einsetzen.

Der Nachteil: Es liegt auf der Hand. Was ist, wenn sich im Verlauf des Projektes doch Änderungen ergeben? Die Corporate-Farben sind dann nicht mehr Rot und Grau sondern Grün und Blau. Und auch wenn die Änderungen bezahlt werden, niemand hat Lust durch eine Website zu gehen und bei 77 Buttons die Klasse zu ändern.

Funktionelle Klassennamen

Die Gestaltung von Elementen mittels funktionellen Klassennamen sorgt dafür, dass Klassen entsprechend ihrer Funktion und Bedeutung auf der Website eingesetzt werden. Wenn wir also einen Button sowohl im Kontaktformular als auch für hervorgehobene Links auf der Website verwenden wollen, könnte die Klasse .btn-primary eine gute Lösung sein. Oder, um mal ein Beispiel aus Contao zu nennen: die Klasse .block, die in Contao bei nahezu allen Modulen und Elementen in Contao enthalten ist.

Der Vorteil: Funktionelle Klassennamen lassen sich ganz unabhängig von ihrem Kontext wiederverwenden. Wo immer ein roter Button gebraucht wird, hängen wir dem entsprechenden Element einfach die Klasse .button-primary an. Dennoch ist das Schema nachvollziehbar und die Benennung noch einigermaßen gut durch -secondary und ggf. -tertiary erweiterbar, wenn man im Projektverlauf noch andersfarbige Buttons benötigt. Und wenn es wirklich dazu kommt, dass die Firmenfarben sich ändern, müsst ihr nicht durch die gesamte Seite gehen und die Klassen umbenennen, sondern es reichen wenige Änderungen in den Stylesheets. Auch in puncto Performance haben funktionelle Klassen einen Vorteil: je nach Projektgröße lassen sich von ein paar Zeilen bis zu ein paar Kilobyte CSS sparen.

Der Nachteil: Im Vergleich zu den kontextbezogenen und beschreibenden Klassennamen sind die funktionellen Klassennamen in der Regel weniger intuitiv. Entwickler müssen sich also erst einen genauen Überblick über einen Großteil der Stylesheets verschaffen, um den Sinn und die Bedeutung dieser Klassennamen nachvollziehen zu können.

ZL;NG

Wann immer möglich, solltet ihr auf funktionelle Klassen setzen. Gerade für größere/wachsende Projekte sind sie die bessere Wahl und sollten gegenüber kontextbezogenen und beschreibenden Klassen bevorzugt werden.

Kompass grau

2. Der ideale Aufbau eines Klassennamens

Ich sprach ja eingangs davon, dass die Benennung weniger ein Problem von mangelnder Kreativität ist. Zu kreativ sollte man allerdings auch nicht werden:

Standardisierung

Versucht bei euren Klassennamen das große Ganze zu sehen. Im Idealfall sollten die Bezeichnungen so standardisiert sein, dass man sie auch bei einem anderen Projekt wiederverwenden könnte:

gut: *.team-member {…}* oder *.contact-person {…}*
besser: *.profile {…}*

Relevanz

Die wichtigsten Eigenschaften eurer Klasse sollten immer vorne stehen. Wir teilen einen Klassennamen in unterschiedliche Teile ein:

  • [group] - Gruppenname, falls Element so oder in ähnlicher Form auf der Seite vorhanden
  • [identifier] - Die eigentliche Bezeichnung der Klasse
  • [child] - Ergänzung, falls es sich um ein Kindelement handelt
  • [modifier] - Status eines Elements

Und genau in dieser Reihenfolge versuchen wir auch unsere Klassen aufzubauen, also [group][identifier][child][modifier]. Zur besseren Nachvollziehbarkeit hier ein paar Beispiele:

kann man machen: .main-nav
besser: .nav-main [group][identifier]

kann man machen: .small-logo
besser: .logo-small [identifier][modifier]

kann man machen: .big-headline-highlight
besser: .highlight-headline-big [identifier][child][modifier]

Interaktion

Ab und an kommt es vor, dass eure Klassen mit Javascript interagieren sollen (wenn ihr nicht auf data-Attribute ausweichen könnt). Wenn eure Klassen einzig dafür gedacht sind, um Inhaltsblöcke für eure Scripte zu markieren, dann solltet ihr auch die Klassen entsprechend kennzeichnen, z.B. indem ihr eurer Klasse ein .js- voranstellt. So kommt ihr auch weniger in Versuchung, die Klasse im Zuge einer Optimierung versehentlich zu löschen.

ZL;NG:

Wir empfehlen Klassennamen nach folgendem Prinzip aufzubauen:

.[js-][group][identifier][child][modifier]

Steuerrad grau

Wie sinnvoll ist es die Contao-Klassen zu nutzen?

Jetzt habe ich lang und breit über die Bezeichnung von eigenen Klassen gesprochen, aber wie sieht es eigentlich mit den contaoeigenen Klassen aus?

Standardmäßig kommt Contao ja bereits mit einer Vielzahl von Klassen mit. Jedes Modul, sei es das Navigationsmenü (.mod_navigation), eine News-Liste(.mod_newslist), selbst ein ganz normaler Artikel (.mod_article) und jedes Element (z.B. .ce_text) bringen ihre eigenen Klassen mit. Da liegt es doch nahe, diese Klassen einfach zur Umsetzung eines Designs zu nutzen, oder?

Vorteile, die contaoeigenen Klassen zu verwenden

Das Schöne an den contaoeigenen Klassen wie zum Beispiel .mod_navigation ist, dass sie automatisch dabei sind. Ich kann also nicht vergessen, diese Klassen hinzuzufügen und ich muss sie auch nicht jedes Mal festlegen. Auch wenn die Website von einem weniger versierten Kunden gepflegt wird, müssen wir uns keine Sorgen machen. Die Klassen sind einfach da.

Nachteile, die contaoeigenen Klassen zu verwenden

Während ich in den Anfängen meiner Contao-Zeit noch Navigationen und andere Module mit IDs gestaltete (warum IDs generell keine gute Idee sind, werden wir nächste Woche behandeln), ging ich im Verlaufe der letzten Jahre dazu über, unsere Projekte mit den contaoeigenen Klassen zu gestalten. Um eine Navigation aber explizit ansprechen zu können, musste ich sie dann abhängig von der Position im Layout stylen, also z.B. #header .mod_navigation. Das wiederum bedeutete aber, dass das Styling kontextbezogen war und dementsprechend die gleichen Nachteile wie oben beschrieben bei den kontextbezogenen Klassennamen mitbrachte.

Es kamen aber noch weitere Einschränkungen hinzu:

Namenskonventionen

Die Namensgebung der Contao-Klassen ist recht leicht nachzuvollziehen: Alle Content Elemente beginnen mit .ce_ + Art des Elements, alle Module beginnen mit .mod_ + Art des Moduls.

Innerhalb der Container gibt es zwar ein paar Gemeinsamkeiten, (z.B. .layout_ bei News und Events) aber im Grunde genommen war Leo beim Aufbau der anderen Klassen dann etwas freier.

Die Frage ist, entspricht die Namenskonvention mit .mod_ und .ce_ eurer eigenen Schreibweise? Wenn ja … Glückwunsch! Wenn nicht, dann werdet ihr vermutlich immer zwischen der Contao-Schreibweise und eurer eigenen Benennung hin- und herspringen.

Mir persönlich ist .mod_navigation zu lang, weshalb ich Navigationen lieber mit nav abkürze. Den Hinweis, ob es sich um ein Element oder Modul handelt, lasse ich ebenfalls weg. Mir gehen die Klassen so beim Schreiben besser von der Hand und ich finde mich in meinen Anweisungen besser zurecht.

Gemeinsame CSS-Anweisungen für mehrere Elemente und Module

Im Laufe der Zeit, und auch bei größeren Projekten, kam es immer häufiger vor, dass ich Anweisungen auf mehrere Elemente oder Module, ungeachtet ihrer Art, anwenden wollte.

Wenn ich heute News und Events gestalte, dann haben beide Module meist eine sehr ähnliche Gestaltung. Das Problem: News und Events arbeiten mit unterschiedlichen Klassen, bei der Listenansicht zum Beispiel mit .mod_newslist und .mod_eventlist.

Will man an dieser Stelle dennoch mit den contaoeigenen Klassen arbeiten, dann würde man die Selektoren im besten Fall durch Kommata getrennt aufführen:

.mod_newslist,
.mod_eventlist {
	background: #bbb;
	…
}

.mod_newslist > div,
.mod_eventlist > div {
	padding: 20px;
	border-bottom: 2px solid #bbb;
	…
}

Wenn dann allerdings noch weitere Module wie .mod_newsarchive und .mod_faqlist dazu kommen, dann wird es langsam aber sicher unübersichtlich.

Dabei ist die Alternative so leicht: Einfach selbst eine Klasse benennen und diese über die Experteneinstellungen den Modulen und Content Elementen zuordnen. Wir sparen uns so nicht nur ein paar Selektoren, sondern sorgen so im Idealfall auch gleich dafür, dass weitere Module und Elemente in Zukunft auf sehr einfache Weise und im gleichen Stil gestaltet werden können.
Wenn ihr euch mal die Contao Demo und dort speziell die News und Events im Footer anschaut, dann versteht ihr was ich meine.

ZL;NG:

Sobald Projekte etwas größer werden, ist es besser auf eigene Klassen zu setzen, da sie sich auch modul- und elementtypübergreifend verwenden lassen.

Wie sieht es in der Praxis aus?

Ich muss zugeben, dass obwohl wir versuchen, auf contaoeigene Klassen zu verzichten und uns so ein Höchstmaß an Flexibilität beizubehalten, es nicht unbedingt immer praktikabel ist.

In manchen Situationen würde das bedeuten, dass wir entweder jedem Element eine Klasse über die Experteneinstellungen zuordnen oder einen Großteil der Templates anpassen müssten. An manche Stellen käme man ohne Template-Anpassungen gar nicht erst heran.

Deswegen habe ich mich mal ein wenig umgesehen und bin auf einen Artikel von Marc Reimann in der Screen Guide gestoßen. Schon länger stand im Raum, ob man nicht eine Konfigurationsdatei schaffen könnte, in der sich nahezu alle Klassen, die im System verwendet werden, anpassen ließen. Die Lösung für unser Problem.

Aus dem Vorschlag, diese Möglichkeit in den Contao-Core mit aufzunehmen, ist leider nichts geworden. Allerdings hat Yanick Witschi a.k.a Toflar daraufhin die Erweiterung Contao CSS class replacer geschrieben, die es ermöglichen soll, dass man jedem x-beliebigen Modul oder Element neue Klassen hinzufügt, bestehende modifiziert oder entfernt.

In ersten Tests macht die Erweiterung einen sehr guten Job. Allerdings schreibt Yanick auch dazu, dass man immer im Hinterkopf behalten sollte, dass die Erweiterung zu Lasten der Performance geht. Je mehr Regeln, desto mehr Auslastung, bzw. desto länger dauert es. Das Seitencaching sollte also besser aktiviert sein.

Unser Fazit:

Gerade bei größeren Webprojekten solltet ihr bei der Klassenbezeichnung darauf achten, funktionelle Klassennamen einzusetzen und diese so strukturieren, dass sich diese gut wiederverwenden lassen. Die contaoeigenen Klassen sind dafür eher nicht geeignet, weshalb ihr sie lieber meiden solltet. Macht euch auch Gedanken über eine einheitliche Namenskonvention beim Schreiben von CSS.

Was wir uns in Zukunft von Contao wünschen würden, wäre eine Möglichkeit, die Klassenbezeichnungen im Contao-Core selbst bestimmen zu können. Denn momentan lassen sich CSS-Schreibweisen wie BEM, dass wir begonnen haben für unsere Projekte einzusetzen, nicht stringent durchsetzen. Zumindest nicht, ohne große Teil der Template anzupassen oder die oben erwähnte Contao-Erweiterung.

Kommentare

Kommentar von Sascha |

Hallo Dennis,
einen ähnlichen Ansatz wie Du verfolge ich mittlerweile ebenfalls. BEM hab ich mal in Betracht gezogen, konnte es jedoch nicht für mich adaptieren.

Generelle Dinge wie margin und padding der ul spreche ich gern, soweit möglich, ohne die Klasse über das nav-Tag an. Für das funktionale Styling will ich in Zukunft wieder auf funktionale Klassen wie nav_h (horizontal), nav_v (vertikal), nav_dropdown zurückgreifen. So sind alle Klassen projektübergreifend wiederverwendbar.
Erst bei reinen Layoutanpassungen wie Farben und ähnliches würd ich das Modul über eine direkte Klasse wie nav_main, nav_meta, nav_sub, ... ansprechen.

Den "Contao CSS class replacer" finde ich große Klasse und ich hab mich sehr gefreut als Yanick sich entschloss das Modul zu programmieren. An dieser Stelle nochmal herzlichen Dank für Deine Arbeit Yanick :-)

Kommentar von Philipp |

Hi Dennis,
guter Artikel. Ich finde mich darin wieder :-)
Hast du denn ein Tipp oder Tool, wo man eine bestehende Website auf überflüssiges oder veraltetes CSS überprüfen kann? Damit man eventuell mal seinen Contao-CSS-Wirrwarr angehen und Struktur wieder reinbringen kann?
Bei Webseiten, an denen immer wieder gearbeitet wird, verliert man sich in seinem eigenen CSS-Code und hängt irgendwann nur noch neue Klassen ran. Und wenn die nicht greifen macht man ein schön, ekliges !important :-)

Gruß Philipp

Antwort von Dennis Erdmann

Das Tool CSS Stats geht glaube ich in die Richtung von dem, was du suchst. Mehr Infos folgen in einem der nächsten Artikel.

Was ist die Summe aus 5 und 3?