Benutzer-Werkzeuge

Webseiten-Werkzeuge


css:guidelines

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu der Vergleichsansicht

css:guidelines [2015/12/03 19:32] (aktuell)
Zeile 1: Zeile 1:
 +====== CSS Guidelines ======
  
 +Dies ist eine kurze, unvollständige Zusammenfassung der weit ausführlicheren,​ sehr interessanten [[http://​cssguidelin.es|CSS Guidelines]] von [[http://​csswizardry.com|Harry Roberts]]. Sie dient nur mir persönlich zur Erinnerung an einzelne Punkte; das Lesen der gesamten CSS Guidelines ist dringend empfohlen.
 +
 +
 +
 +===== Namenskonventionen =====
 +
 +Die folgenden Namenskonventionen helfen nicht direkt beim Schreiben der CSS. Im HTML beschreiben die Klassennamen allerdings, wie einzelne Elemente miteinander im Verhältnis stehen. Dies sorgt bei größeren Projekten für mehr Transparenz und unterstützt so die Teamkollegen.
 +
 +==== Allgemein ====
 +  * Namen werden ausschließlich durch Bindestriche verknüpft, z.B. ''​page-head''​
 +  * Bedeutet: keine Unterstriche,​ kein camelCase!
 +  * JavaScript: Eigene Klassennamen für JS verwenden, um unabhängig zu bleiben; z.B. ''​%%class="​btn ​ js-btn"​%%''​
 +  * Bei zusammenhängenden,​ verschachtelten Elementen wird **BEM** (Block, Element, Modifier) verwendet:
 +
 +**Block:** ein eigenständiger Bestandteil einer Website\\
 +**Element:​** ein Bestandteil,​ welches vom Block abhängig ist\\
 +**Modifier:​** eine Anpassung oder Erweiterung des Blocks oder Elements
 +
 +==== Schreibweise ====
 +.block {}\\
 +%%.block__element {}%%\\
 +%%.block--modifier {}%%
 +
 +==== Regeln ====
 +  * Die Klassenbezeichnung soll nicht die DOM-Struktur abbilden (zu lange Klassennamen)!\\
 +    * Gut: Ein Modifier ''​%%person__eye--blue%%''​
 +    * Schlecht: Verschachtelte Unterelemente ''​%%.person__head__eye%%'',​ stattdessen:​ ''​%%.person__eye%%''​
 +  * Elemente direkt mit Klasse ansprechen: ''​%%.nav__item%%''​ statt ''​%%.nav__list li {}%%''​
 +  * BEM soll nicht überall angewendet werden. Aus ''​.logo''​ innerhalb des Headers muss nicht ''​%%header__logo%%''​ werden! ​
 +  * //to be continued ...//
 +
 +==== Beispiel ====
 +<code html>
 +<div class="​nav ​ nav--main ​ block">​
 +    <ul class="​nav__list ​ level_1">​
 +        <li class="​nav__item"><​a>​Home</​a></​li>​
 +        <li class="​nav__item"><​a>​About us</​a></​li>​
 +        <li class="​nav__item"><​a>​Imprint</​a></​li>​
 +    </ul>
 +</​div>​
 +</​code>​
 +
 +
 +
 +===== CSS-Selektoren =====
 +
 +==== Wahl des Selektors ====
 +
 +Die gewünschte Absicht ist immer die Grundlage für die Wahl der Selektoren.
 +
 +Wenn es die Absicht ist, das Hauptmenü im Header zu gestalten, sollte man nicht
 +<code css>
 +header ul {}
 +// oder
 +.header ul {}
 +</​code>​
 +verwenden, da dies alle eventuell im Header befindlichen Listen trifft. Wird dort nachträglich eine Liste hinzugefügt,​ müsste man die CSS-Deklarationen der neuen Liste wieder überschreiben oder aber das ursprüngliche Hauptmenü ab diesem Zeitpunkt anders ansprechen.
 +
 +Besser ist daher
 +<code css>
 +.site-nav {}
 +</​code>​
 +als eindeutiger Selektor für das gewünschte Ergebnis.
 +
 +==== Wiederverwendbarkeit ====
 +
 +Für einen Komponenten-basierten Ansatz bei der Entwicklung von Websites ist es wichtig, Klassen innerhalb eines oder auch verschiedener Projekte wiederverwenden zu können.\\
 +Erhöhe hierfür die Anzahl der verwendeten Klassen innerhalb eines HTML-Elements und teile die CSS-Deklarationen sinnvoll auf (siehe auch "​Architekturprinzipien"​). IDs sollten nicht für das Styling verwendet werden, da sie nur einmal pro Seite vorkommen können und zu stark gewichtet sind.
 +<code html>
 +<div class="​box ​ box--large ​ promo">​
 +</​code>​
 +
 +==== Unabhängigkeit vom Einsatzort ====
 +
 +Gestalte ein Objekt nicht abhängig davon, **wo** sie sind, sondern **was** sie sind. So kann es an anderer Stelle wiederverwendet (und ggf. mit einem Block-Modifier angepasst) werden.
 +
 +Beispiel eines //​Call-to-Action//​-Buttons innerhalb einer Promotion-Box:​
 +<code css>
 +// Schlecht:
 +.promo a {}
 +
 +// Besser:
 +.btn {}
 +</​code>​
 +
 +==== Übertragbarkeit einer Klasse ====
 +
 +Selektoren sollten nicht von HTML-Elementen abhängig sein, z.B.
 +<code css>
 +// Schlecht:
 +input.btn {}
 +</​code>​
 +Diese Klasse ließe sich nicht auf andere HTML-Elemente anwenden und bringt in dieser Form auch keinen Mehrwert für die //​input//​-Elemente.\\
 +Falls es darum geht, zusätzliche CSS-Deklarationen bei einem bestimmten HTML-Element hinzuzufügen,​ wäre diese Herangehensweise okay, es ginge aber auch besser:
 +<code css>
 +// Okay:
 +/* Fehlermeldungen allgemein */
 +.error {
 +  color: red;
 +  font-weight:​ bold;
 +}
 +
 +/* Falls das Element ein div ist, wird es zudem als Box gestaltet */
 +div.error {
 +  border: 1px solid;
 +  padding: 10px;
 +}
 +
 +
 +// Besser:
 +.error-text {
 +  color: red;
 +  font-weight:​ bold;
 +}
 +
 +.error-box {
 +  border: 1px solid;
 +  padding: 10px;
 +}
 +</​code>​
 +
 +==== Namensgebung ====
 +
 +Aus Gründen der Wiederverwendbarkeit sollte man Namen wählen, die sinnvoll, aber nicht zu eindeutig sind:
 +  * ''​.primary-nav''​ statt ''​.site-nav''​
 +  * ''​.sub-links''​ statt ''​.footer-links''​
 +
 +Während ''​.footer-links''​ die Verwendung auf den Footer begrenzt, kann ''​.sub-links''​ auch an anderer Stelle verwendet werden.
 +
 +Bezeichnungen sollten weder den konkreten Einsatzzweck noch die genaue Deklaration beschreiben:​
 +<code css>
 +// Schlecht: Die Farbe könnte sich mal ändern
 +.blue {
 +  color: blue;
 +}
 +
 +// Schlecht: Ist vom Einsatzort abhängig
 +.header span {
 +  color: blue;
 +}
 +
 +// Schlecht: Zu spezifisch, kann schlecht wiederverwendet werden
 +.header-color {
 +  color: blue;
 +}
 +
 +// Gut: wiederverwendbar,​ unabhängig von späteren Änderungen
 +.highlight-color {
 +  color: blue;
 +}
 +</​code>​
 +
 +
 +==== Performance von Selektoren ====
 +
 +Bei der Qualität der heutigen Browser ist es eher interessant als wichtig, wie schnell CSS-Selektoren den Knoten im DOM zugeordnet werden können.
 +
 +Im Allgemeinen gilt: Je komplexer ein Selektor, desto aufwändiger ist er für den Browser zu verarbeiten.
 +
 +<code css>
 +body.home div.header ul {}
 +</​code>​
 +
 +Browser lesen Selektoren von rechts nach links. Daher muss er folgende Arbeitsschritte durchführen:​
 +  * finde alle ul-Elemente im DOM
 +  * prüfe nun, ob diese irgendwo innerhalb eines Elements mit der Klasse ''​.header''​ vorkommen
 +  * prüfe jetzt, ob die ''​.header''​ Klasse zu einem div gehört
 +  * prüfe nun, ob sich dies alles innerhalb eines Elements mit der Klasse ''​.home''​ befindet
 +  * prüfe als letztes, ob ''​.home''​ die Klasse des body-Elements ist
 +
 +Hinzu kommt, dass sich zwischen ''​body.home'',​ ''​div.header''​ und ''​ul''​ weitere Elemente befinden können. Daher sucht der Browser solange dem DOM entlang nach dem nächsten Teilselektor,​ bis er ihn gefunden hat. Dies kann man zumindest mit ''​foo > bar''​ beheben, indem man den Browser nur die nächste Ebene durchsuchen lässt.
 +
 +Logischerweise ist der folgende Selektor wesentlich effizienter:​
 +<code css>
 +.primary-nav {}
 +</​code>​
 +
 +==== Der Schlüssel-Selektor ====
 +Da Browser die Selektoren von rechts nach links verarbeiten,​ ist der letzte (rechte) Teilselektor der //​Schlüssel-Selektor//​
 +
 +Ein Extrembeispiel ist das folgende: So einfach der Selektor zuerst erscheint - schließlich kann eine ID nur einmal vorkommen - so verzwickt wird es mit dem Schlüssel-Selektor ''​*''​.
 +<code css>
 +#foo * {}
 +</​code>​
 +Dieser würde wirklich *alle* Knoten im DOM (inkl. ''<​head>'',​ ''<​title>''​ und ''<​link>''​) finden und dann im nächsten Schritt abgleichen, welche dieser Elemente sich innerhalb von ''#​foo''​ befinden.\\
 +
 +==== Zusammenfassung ====
 +
 +  * Wähle das gewünschte Element direkt aus, statt es vom Umfeld abhängig zu machen.
 +  * Verwende viele Klassen, vermeide IDs; teile CSS-Deklarationen sinnvoll auf Klassen auf, um sie wiederverwenden zu können.
 +  * Verschachtele Selektoren nicht unnötig, da es den Einsatzzweck zu genau bestimmt und dies Einfluss auf die Wiederverwendbarkeit hat.
 +  * Beschränke den Selektor nicht unnötig auf ein bestimmtes HTML-Element.
 +  * Halte Selektoren so kurz wie möglich.
 +
 +
 +
 +===== Gewichtung (Spezifizierung) =====
 +
 +Hat jeder schon erlebt - eine ID im allgemeineren Selektor und die spezielle Klasse wird ignoriert:
 +<code css>
 +#content table {}
 +
 +// diese Klasse wird immer vom oberen Selektor überschrieben:​
 +.my-new-table {}
 +</​code>​
 +Was tun, wenn es zu umständlich wird, das bestehende Projekt umzubauen? Der neue Selektor muss noch eine noch stärkere Gewichtung erhalten! Und wenn ich später eine weitere Variante einführen möchte? ... damit setzt man eine Abwärtsspirale in Gang, die Selektoren müssen eine immer stärkere Gewichtung erhalten.
 +
 +Am besten hält man die Gewichtung möglichst niedrig, indem man
 +  * keine IDs in Selektoren verwendet,
 +  * Selektoren nicht verschachtelt,​
 +  * Klassen nicht an HTMl-Elemente bindet,
 +  * nicht mehrere Klassen im Selektor verwendet.
 +
 +
 +==== !important ====
 +
 +Wer die Gewichtung niedrig hält, wird ''​!important''​ nicht gebrauchen müssen, um Fehler auszubügeln.\\
 +Seine Daseinsberechtigung hat das Schlüsselwort vor allem bei proaktivem Gebrauch, also wenn es nichts reparieren soll, sondern die Funktion von Vornhinein sicherstellen:​
 +<code css>
 +.hidden {
 +  display: none !important;
 +}
 +</​code>​
 +Wer diese Klasse an einem HTML-Element verwendet, möchte auf jeden Fall, dass es nicht angezeigt wird.
 +
 +
 +==== Gewichtung steuern ====
 +
 +Irgendwann kommt immer der Punkt, an dem man trotz geringer Gewichtung etwas tricksen muss.
 +
 +Wenn ein Selektor mit zwei Klassen überschrieben werden muss, kann man einfach den Schlüssel-Selektor zweimal notieren (ohne Leerzeichen). So bleibt auch die Übertragbarkeit in andere Seitenbereiche gegeben.
 +
 +<code css>
 +// muss überschrieben werden:
 +.header .nav {}
 +
 +// Lösung: dieselbe Klasse zweimal im Selektor, ohne Leerzeichen:​
 +.nav.nav {}
 +</​code>​
 +
 +Falls mal ein HTML-Element mit ID gestaltet werden muss, dessen Quellcode man nicht um eine Klasse ergänzen kann, hilft folgender Trick:
 +
 +<code css>
 +// Handhabung der ID als Attribut:
 +[id="​third-party-widget"​] {}
 +</​code>​
 +
 +
 +
 +===== Architekturprinzipien =====
 +
 +CSS ist keine Programmiersprache,​ dennoch kann es hilfreich sein, ein Architekturprinzip als Grundlage für seine Stylesheets zu nutzen. Gerade bei größeren Projekten mit Teamarbeit sorgt dies für eine einheitliche,​ skalierbare Arbeitsweise.
 +
 +Architekturen sind jeweils allumfassende Sammlungen von Richtlinien,​ die dem Anwender eine reglementierte Grundlage für seine Arbeit bieten. Details wie Syntax oder Namensgebungen bleiben hierbei üblicherweise dem Anwender überlassen.
 +
 +Die gewählte Architektur sollte
 +  * eine vernünftige,​ einheitliche Grundlage bieten,
 +  * Änderungen ermöglichen,​
 +  * Skalierung der Codebasis sicherstellen,​
 +  * Wiederverwendbarkeit und Effizienz fördern,
 +  * Produktivität steigern.
 +
 +Für gewöhnlich führt dies zu einer Klassen- und Komponenten-basierten Arbeitsweise,​ in übersichtliche Module aufgeteilt. Ein Präprozessor wie SASS oder LESS ist hier hilfreich.
 +
 +==== Objektorientierung (OOCSS) ====
 +
 +Bei objektorientiertem CSS wird das User Interface in **Struktur** und **Erscheinungsbild** unterteilt: UI-Komponenten werden auf ihre formgebenden Teile (Abstände, Layout, ...) reduziert und können über separate Klassen um ihre gewünschte Gestaltung (Farben, Schriften, ...) ergänzt werden.
 +
 +Man kann sich die Struktur als ein Grundgerüst vorstellen, eine wiederverwendbare Vorlage ohne weitere Gestaltung.
 +<code css>
 +.btn {
 +  display: inline-block;​
 +  padding: 1em 2em;
 +  vertical-align:​ middle;
 +}
 +
 +.btn--positive {
 +  background-color:​ green;
 +  color: white;
 +}
 +
 +.btn--negative {
 +  background-color:​ red;
 +  color: white;
 +}
 +</​code>​
 +<code html>
 +<button class="​btn ​ btn--negative">​Delete</​button>​
 +</​code>​
 +Die ''​.btn''​-Klasse gibt dem button-Element lediglich die gewünschte Struktur, das Erscheinungsbild wird von einer separaten Klasse gesteuert. So ist ''​.btn''​ in jedem neuen Projekt wiederverwendbar.
 +
 +
 +==== Das Single-Responsibility-Prinzip ====
 +
 +Laut diesem Prinzip hat jede Klasse nur eine fest definierte Aufgabe zu erfüllen. Bezogen auf CSS werden Deklarationen in kleinere Blöcke aufgeteilt. Jede Deklaration ist nur noch für einen Zweck da und wird für das gewünschte Ergebnis mit weiteren kombiniert.
 +<code css>
 +.error-message {
 +  display: block;
 +  padding: 10px;
 +  border-top: 1px solid #f00;
 +  border-bottom:​ 1px solid #f00;
 +  background-color:​ #fee;
 +  color: #f00;
 +  font-weight:​ bold;
 +}
 +
 +.success-message {
 +  display: block;
 +  padding: 10px;
 +  border-top: 1px solid #0f0;
 +  border-bottom:​ 1px solid #0f0;
 +  background-color:​ #efe;
 +  color: #0f0;
 +  font-weight:​ bold;
 +}
 +</​code>​
 +Diese beiden Klassen steuern Layout, Struktur und Gestaltung; viele Deklarationen wiederholen sich. Wenn man dieses CSS anhand von OOCSS umschreibt und dabei noch das Single-Responsibility-Prinzip anwendet, erhält man vier kleinere Klassen:
 +<code css>
 +.box {
 +  display: block;
 +  padding: 10px;
 +}
 +
 +
 +.message {
 +  border-style:​ solid;
 +  border-width:​ 1px 0;
 +  font-weight:​ bold;
 +}
 +
 +.message--error {
 +  background-color:​ #fee;
 +  color: #f00;
 +}
 +
 +.message--success {
 +  background-color:​ #efe;
 +  color: #0f0;
 +}
 +</​code>​
 +Jetzt haben wir ein allgemeines "​Box"​-Objekt erhalten, dass wir an vielen Stellen wiederverwenden können, ebenso wie ein "​Nachrichten"​-Objekt,​ dass mit den beiden anderen Klassen erweitert werden kann.
 +
 +
 +==== Das Open-Closed-Prinzip ====
 +
 +Dieses Prinzip gehört ebenfalls zur objektorientierten Programmierung. Es besagt, dass Module **für Erweiterungen offen** sein sollen, aber **geschlossen gegenüber Modifikationen**.
 +
 +Bei CSS werden Anpassungen demnach nicht direkt an der bestehenden Klasse vorgenommen,​ sondern anhand einer zweiten:
 +<code css>
 +// Falsch:
 +.box {
 +  display: block;
 +  padding: 10px;
 +}
 +.content .box {
 +  padding: 20px;
 +}
 +
 +// Richtig:
 +.box {
 +  display: block;
 +  padding: 10px;
 +}
 +.box--large {
 +  padding: 20px;
 +}
 +</​code>​
 +Beim schlechten Beispiel wird die Anpassung über einen unnötig stark gewichteten,​ einsatzortabhängigen Selektor vorgenommen - und die ''​.box''​-Klasse wird direkt überschrieben,​ was dem Open-Closed-Prinzip widerspricht. Der Teamkollege kann sich nicht länger auf die ursprüngliche Funktion der ''​.box''​-Komponente verlassen! \\
 +
 +
 +==== DRY: Don't Repeat Yourself! ====
 +
 +Laut diesem Prinzip sollte man Wiederholungen auf ein nötiges Minimum reduzieren. Man darf es nicht übertreiben,​ da man sonst zu komplizierten Code schreibt und unpraktische Abhängigkeiten entstehen können.
 +
 +<code css>
 +.btn {
 +  display: inline-block;​
 +  padding: 1em 2em;
 +  font-weight:​ bold;
 +}
 +.page-title {
 +  font-size: 3rem;
 +  line-height:​ 1.4;
 +  font-weight:​ bold;
 +}
 +.user-profile__title {
 +  font-size: 1.2rem;
 +  line-height:​ 1.5;
 +  font-weight:​ bold;
 +}
 +</​code>​
 +Obwohl hier dreimal ''​font-weight:​ bold;''​ auftaucht, ist es unsinnig, diese Deklaration auszulagern und über ein //mixin// oder ''​@extend''​ einzufügen.\\
 +Wenn jedoch z.B. ein Webfont verwendet wird, der bei jeder Nutzung über ''​font-family''​ auch ein ''​font-weight:​ bold;''​ benötigt, haben wir einen sinnvollen Einsatz gefunden:
 +<code css>
 +@mixin my-web-font() {
 +    font-family:​ "My Web Font", sans-serif;
 +    font-weight:​ bold;
 +}
 +
 +.btn {
 +  display: inline-block;​
 +  padding: 1em 2em;
 +  @include my-web-font();​
 +}
 +.page-title {
 +  font-size: 3rem;
 +  line-height:​ 1.4;
 +  @include my-web-font();​
 +}
 +.user-profile__title {
 +  font-size: 1.2rem;
 +  line-height:​ 1.5;
 +  @include my-web-font();​
 +}
 +</​code>​
 +Wenn der Webfont nun ausgetauscht werden soll und dadurch auf ''​font-weight:​ normal;''​ umgestellt werden muss, wird dies nur an einer zentralen Stelle nötig.
 +
 +Man sollte also nur Wiederholungen reduzieren, wo eine thematische Verbindung besteht.
css/guidelines.txt · Zuletzt geändert: 2015/12/03 19:32 (Externe Bearbeitung)