• aktuell
  • über mich
  • mein blog
  • impressum

CSS|diverse Konzepte

Immer mehr Webseiten entwickeln sich zu sogenannten Web Apps und nutzen wiederverwendbare Komponenten. Dadurch entwickelte sich eine neue Herangehensweise. CSS-Code muss nicht mehr in separaten Stylesheet-Dateien ausgelagert werden, sondern man kann den Style-Code auch in JavaScript verfassen - eben Css in Js.

Kommt jemand vom Programmieren, weiß Der-/Diejenige schon nach kurzer Zeit, warum globale Variablen umständlich anzuwenden sind. Wohingegen in CSS globale Regeln fast schon zur guten Architekturmanier gehören.

Darüber hinaus gibt es Ansätze, die man nicht direkt begreift. Beispielsweise ist die Kaskade, die sogar im Namen CSS - Cascading Style Sheet enthalten ist, die Vererbung und beschreibt die Art und Weise wie CSS-Eigenschaften interagieren und zusammenwirken. Zum Cascading zählt auch die Eigenschaft, die definiert, wann eine bestimmte Regel/Klasse Vorrang vor der Anderen hat. Schaut man sich mal folgende HTML-Code an:

<p class="important"></p>

und dazu das CSS:

.important {
color: red;
}

p {
color: blue;
}

Hier wird die Bedeutung der Kaskadierung deutlich: Prinzipielle Formatierung definieren und dann über Klassen die Ausnahme bestimmen.

CSS Regeln

Selbst die einfachsten CSS-Beispiele, können riesige Fragezeichen aufwerfen.

.red {
  color: red;
}
    
.blue {
  color: blue;
}

Welche Farbe haben die div-Elemente?

<div class="red blue">Hello</div>
<div class="blue red">World</div>

Die richtige Antwort lautet: Beide div-Elemente sind <span style=„color: blue“>blau. Erklärung: Die zweite Klasse .red überschreibt .blue und deshalb gelten die Style-Angaben von .red . Es fällt auf, dass eben diese Reihenfolge absolut irrelevant ist.

Bei riesigen und komplexen Webprojekten mit etlichen Komponenten, die dazu noch viele Style-Dateien haben, könnten Entwickler schnell den Überblick verlieren. Dazu kommt noch, dass globale Regeln von CSS häufig verwendet werden und, dass man nicht benötigten CSS-Code nicht ohne immensen Aufwand entfernen kann.

Per se gelten Formatierungen bei CSS immer für den ganzen DOM (Document Object Model). Wenn das Dokument aus diversen Komponenten besteht, kann es zur Interaktion der unterschiedlichen Stile kommen. Beispielsweise, weil man ähnliche Buttons gleich benannt hat oder durch das Verschachteln wie in {less} oder Sass den Überblick leicht verliert. In solchen Fällen ist es natürlich effizient, wenn man wie in Angular üblich, das my.component.scss in der jeweiligen Komponente hat. Das machen CLIs der gängigen Frontend-Frameworks/Libraries mittlerweile von ganz selbst - vorausgesetzt man benutzt die generate-Commands.

Nicht benötigten Css-Code löschen

CSS-Code, der nicht mehr benötigt wird, kann viel Zeit fressen, denn Stylesheets können schnell sehr groß werden. Deshalb sollte man nicht genutzte Regeln entfernen. Wann ist es sinnvoll, diese folgende Klasse zu entfernen?

.btn--red {
	color: red;
}

Eine Möglichkeit ist es - unabhängig von der Idea(Entwicklungsumgebung wie Webstorm/PHPStorm etc.) - den ausgespuckten HTML-Code nach der überflüssigen Klasse zu durchsuchen. Man wird aber wohl nichts finden, wenn der Name der Klasse bspw. mit Javascript zusammengesetzt wird. Also müsste man auch in diesem JS-Code nachgucken. Hinzukommt, dass das bei großen und komplexen Seiten sehr mühsam ist, diejenige Klasse zu finden, von der man zu 100% ausgehen kann, dass sie nicht mehr genutzt wird.

Die behandelten Probleme sind nicht neu und es gibt natürlich innerhalb von CSS Lösungsstrategien, die diese Konflikte auffangen. Beispiele dafür sind: OOCSS SMACSS BEM

BEM - Block Element Modifier

BEM bedeutet Block-Element-Modifier und unterstützt den Entwickler bei der Organisation des CSS-Codes. Dabei liegt der Fokus in der Unterscheidung zwischen Blöcken, Elementen und Modifizierern. Blöcke ähneln Komponenten wie z.B. ein Block für einen Header-Bereich. Elemente sind die einzelnen Bestandteile. Die Klassennamen werden nach dem Prinzip block--modifier-value oder block__elem erstellt:

.btn--submit-disabled {
/* properties hier */
}
.btn--submit-enabled {
/* properties hier */
}

Vorteile:

  1. Styles, die zur btn-Komponente gehören, beginnen mit btn. So lässt sich dieser Code gezielt bearbeiten.
  2. Die Änderungen bzgl. Formatierung wirken nicht global und nicht auf andere Komponenten, sondern immer nur da, wo sie eingesetzt werden. Jedoch muss man sie nur ein einziges Mal im CSS aufführen.
  3. Es handelt sich um Klassen, sprich: man ist unabhängig von der HTML-Struktur und hat keine Probleme mit der Spezifität.

CSS helper classes

Ähnlich wie beim BEM sollen CSS-Hilfsklassen Entwicklern dabei helfen, redundante Stilregeln zu vermeiden.

<h1 class="ml-1 text--align-center">Ich bin eine H1</h1>

ml-1 definiert ein margin-left in der Größe 1. text--align-center bestimmt jedes Element, zu dem es im HTML zugewiesen wird, mittig dargestellt zu werden.

Sass

Präprozessor (seltener auch Präcompiler) wie Sass können Stylesheets kompakt und effektiv mithilfe von Variablen und Loops aufbauen. Das sogenannte Nesting sorgt für die Kürze im Stylesheet. Darüberhinaus lassen sich bestimmte Styles in verschiedene Dateien mit der @import-Deklaration aufteilen. Das sorgt für Übersichtlichkeit. Jede Komponente kann beispielsweise eine SCSS-Datei besitzen, die dann wiederum in die Hauptdatei styles.scss importiert/eingebunden wird.

Was denn nun?

Die formulierten Probleme wie globale Styles, Spezifität, DeadCode Elimination lassen sich auch über Javascript lösen. Ohne, dass man zusätzliche Tools für die zu generierenden Präfixe oder die Minimierung benötigt.

CSS-in-JS

Es gibt viele unterschiedliche CSS-in-JS Bibliotheken. Die richtige Bib zu finden, ist auf CSS in JS einfacher als sich durch die ganzen Docs der einzelnen Bibs durchzukämpfen. Hier werden verschiedene Lösungen für das selbe Probleme angezeigt.

Ich komme jetzt zu einem Beispiel.

Radium

Bevor wir Radium nutzen können, müssen wir folgenden Befehl ausführen:

npm install --save radium

Danach kann man die Datei importieren:

export default Radium(Button);

So kann man Styles definieren. Verwendet wird folgende Objektsyntax:

const style = {
backgroundColor: 'blue',
color: 'black',
':hover': {
	backgroundColor: 'white',
	color: 'white'
	}
};

Die Komponente, die das Style-Element nutzen soll, kriegt eine Zuweisung:

<button style={style}>Button</button>

Hier sieht man den kompletten Code:

import React, {component} from 'react';
import Radium from 'radium';

const Button = () => {
	const style = {
		background: 'white',
		color: 'black',
			':hover': {
			backgroundColor: 'white',
			color: 'white'
		}
	 };
	return {
		<button style={style}>Button</button>
	}
}
export default Radium(Button);

Der große Vorteil bei diesem Vorgehen ist vor allem die Tatsache, dass das der gesamte Code, der zu einer Komponente gehört (Markup, Verhalten, Formatierung) in einer Datei abgebildet ist. Braucht man die Komponente nicht mehr, darf man sie einfach als File löschen und das wars. Keine Abhängigkeiten, die noch bereinigt werden müssen. Die Formatierungen werden durch Radium folgendermaßen im Browser als Inline-styles ausgegeben:

<button style="background-color: blue; color: white;" data-radium="true">Button</button>

Die Pseudo-Klasse :hover wird allerdings als JavaScript ausgegeben. Die sogenannten Event-Listener übernehmen diesen Part:

function foo(e) {
	existingOnMouseEnter && existingOnMouseEnter(e);
	setState(':hover', true);
}

@Media Queries

Styles, die nicht über Inline-Styles wiedergegeben können, etwa Media Queries und/oder Animationen, werden mit Hilfe von Helper gelöst. Pseudo-Klassen wie :checked, :before oder :after müssen mit Javascript implementiert werden. Es ist nicht ganz optimal, Sache, die direkt in CSS implementiert werden können, mit JS zu bauen. Selbstverständlich sollte man immer erstmal auf die nativen CSS-Features achten.

Nicht so cool

Bevor man sich durch die Liste durcharbeitet und sich für eine Lösung entscheidet sollte man sich folgende Dinge vor Augen halten:

  • Möchte man den CSS-Code direkt bearbeiten, wird es nicht mehr nur über eine einzige Datei gehen
  • der CSS-Code lässt sich nicht direkt in einem anderen Projekt weiterverwenden, außer die Technik ist die Selbe
  • keine semantischen Klassennamen und somit auch schwieriger den CSS-Code zu verstehen
  • es werden zusätzliche Bibliotheken geladen, die evtl. die Performance verschlechtern können und Dead Code Elimination nicht so einfach durchführen lässt, weil Styles an Komponenten gebunden sind
  • CSS-in-JS muss nochmal erlernt werden, weil es ein etwas anderes Vorgehen als das klassische CSS ist
  • Syntaxüberprüfung und Autocomplete bieten nicht alle IDEs an
  • Bei unbekannten CSS-in-JS-Lösungen werden langfristig nicht mehr Updates entwickelt und man DEPRECATED-Konflikte

Fazit

Ich persönlich schreibe mein CSS immer sehr gerne in SASS und unterteile die komponentenbezogenen Styles in unterschiedliche .scss-Files. Durchaus sehe ich das Verhältnis der drei grundlegenden Webtechnologie (HTML,CSS,JS) als ein inniges und zum Teil auch verworrenes. Wir leben in einer so schnelllebigen Zeit, dass Frameworks/Libraries/Lösungen in so einer hohen Frequenz publiziert werden, dass das Abwarten immer erstmal gut ist. Vor allem sollte man abwarten, weil das Lernen populärer Tools immer zukunftsorientiert ist. Es sichert dem Entwickler - bezüglich Skillsets - immer an vorderster Front zu sein.

Quellen

  • State of Css
  • Florence Maurice. (2019). CSS in Javascript schreiben. Web&Mobile Developer, 4/19, S.38
  • Radium
  • Block Element Modifier Naming

Bünyamin Tunc

Tuesday, Dec 15, 2020