Wie entscheidet ein Browser, welchen Wert er verwenden soll,
wenn einem Attribut mehrmals unterschiedliche Werte zugewiesen wurden?
Mittels
eines Punktesystems namens Spezifität
(englisch: specificity). Und ja, das heißt tatsächlich so, und es ist nicht etwa bei der Übersetzung aus dem Englischen eine Silbe verloren gegangen.
Mittels Spezifität wird
entschieden, welcher der unterschiedlichen Werte die höchste Relevanz hat.
Zumindest die Grundbegriffe dieser Regeln sollten dem Web-Designer bekannt
sein, wenn es nicht immer wieder zu Überraschungen kommen soll. Dieser Artikel
setzt sich mit eben diesen Grundbegriffen auseinander.
Überraschung, Überraschung…
Eines der ersten Dinge, die man lernt, wenn man beginnt,
sich mit CSS zu beschäftigen, ist, wie man Elemente ansprechen kann: mit den
sogenannten Selektoren.
Wir lernen, dass es ID-, Klassen- und Typ-Selektoren gibt,
und wer schon ein bisschen fortgeschrittener ist, weiß auch um Universal-,
Attribut- und Pseudo-Selektoren.
Und dann kommt irgendwann der Moment, in dem irgendein
Element nicht so will, wie es soll. Beispielsweise eine Schriftfarbe, die ganz
und gar nicht so ausfällt, wie wir das eigentlich erwartet hätten.
Das liegt vermutlich daran, dass hier die Spezifität (specificity) gegriffen hat.
Die Spezifität bestimmt anhand eines Punktesystems, welche
Selektoren schwerer wiegen und daher zum Tragen kommen, wenn ein Wert (oft
unbeabsichtigt) über mehrere Selektoren(-ketten) angesprochen wird.
Eine kleine Auffrischung
Diese vereinfachte Tabellenübersicht gibt einen kurzen
Überblick über die gängigsten Selektoren:
Beispiel
|
Selektor
|
Erklärung
|
p
|
Typselektor
|
Wählt alle <p>-Elemente aus.
|
th, td
|
Element und Element
|
Wählt alle <th>- und
alle <td>-Elemente aus.
|
div p
|
Element in Element
(Nachfahren-Kombinator)
|
Wählt alle <p>-Elemente aus,
die sich in einem
<div>-Element befinden.
|
*
|
Universalselektor
|
Wählt alles aus.
|
.content
|
Klassenselektor
|
Klassenselektor; wählt alle
Elemente mit dieser Klasse (class="content“) aus.
|
#container
|
ID-Selektor
|
Wählt das Element mit der Id (id="container“)
aus.
|
:hover
|
Pseudo-Klassen-Selektor
|
Wählt einen bestimmten Zustand
aus (hier: mouseover).
|
::first-letter
|
Pseudo-Element-Selektor
|
Wählt einen bestimmten Teil
eines Elements aus (hier: den ersten Buchstaben).
|
[a=“xyz“]
|
Attributselektor
|
Wählt ein bestimmtes Attribut (mit
einem bestimmten Wert) aus
|
Das ist einfach genug – wenn man denn die Seite genau genug
geplant hat und das CSS-Dokument kurz, knapp und übersichtlich ist. Leider
entspricht das nicht immer der Praxis. Manche Seiten sind im Lauf der Zeit
gewachsen, sind von anderen Developern übernommen worden, die alle ihren Teil
hinzugefügt haben, und man hat mit Skript-Monstern zu tun, in denen es schwer
ist, überhaupt etwas zu finden. Da kann es leicht vorkommen, dass ein Element von
mehreren Deklarationen angesprochen wird. Genau dann wird Spezifität wichtig.
Verwirrte Browser: Welcher Wert soll verwendet werden?
Wenn nun demselben Attribut mehrere Werte zugewiesen werden,
gibt es Regeln, welcher Wert dann vom Browser zur Darstellung verwendet wird.
Nehmen wir als einfaches Beispiel die Schriftfarbe. Wird ein
Attribut doppelt belegt, wird der Eintrag, der zuletzt kommt, verwendet:
So einfach haben wir es aber leider selten. Unsere
Selektoren sind verknüpft und verschachtelt, und es gibt Klassen und IDs…
Manchmal wird ein Element mit einer Klasse versehen, um ihm
ein gesondertes Styling verpassen zu können – aber nichts passiert. Dann hat
vermutlich die Spezifität zugeschlagen:
In diesem Beispiel wurde versucht, einen bestimmten
Paragraphen innerhalb eines Divs grün zu schreiben. Die Schrift ist allerdings
weiterhin rot – denn der erste Eintrag hat eine höhere Spezifität. (Siehe
Codepen-Beispiel hier.)
Von der höchsten bis zur niedrigsten Spezifität
Während ein paar Regeln, welcher Wert denn nun verwendet
werden soll, intuitiv verständlich und allgemein bekannt sind, ist das
dahinterliegende Prinzip der Spezifität doch etwas komplexer.
Stark vereinfacht gesagt: Es werden Punkte vergeben, und die
Regel mit der höchsten Punkteanzahl „gewinnt“.
Hier ein Kurzüberblick über die Gewichtung der Selektoren:
In vielen Fällen wird das ausreichen, um zu erklären, warum
welcher Wert verwendet wurde, aber natürlich können und werden wir noch etwas
in die Tiefe gehen.
Zur Erklärung der Übersicht:
Inline
Spezifischer, als ein Element im HMTL-Dokument inline
mittels Style-Attribut anzusprechen, geht’s nicht mehr. Damit wird sichergestellt,
dass tatsächlich genau dieses Element gemeint ist, und in der Spezifität
bekommt es die „höchste Punkteanzahl“.
Trotzdem ist inline-CSS normalerweise keine gute Wahl.
Abgesehen davon, dass damit vielleicht auch ungewollt Attributswerte aus dem Stylesheet
überschrieben werden, bläht inline-CSS auch das HTML-Dokument unnötig auf,
macht es unleserlich und für nachfolgende Developer schwer zu finden.
ID
Ein ID-Selektor bekommt die nächsthöhere Priorität. Da eine
ID ein eindeutiger Identifikator eines Elements ist, wird damit ganz genau ein
bestimmtes Element angesprochen. Somit ist die ID von allen Selektoren die spezifischste – daher auch die
Bezeichnung Spezifität. Wird eine ID verwendet, ist die Spezifität auf jeden
Fall höher, unabhängig davon, wieviele Klassen- oder Typselektoren sonst noch
verwendet werden. Das erklärt auch, warum die Schrift im Beispiel oben rot,
nicht grün war.
Class
Eine Klasse kann mehreren Elementen zugeordnet werden. Sie
ist somit weniger spezifisch als eine ID; aber immer noch spezifischer, als
eine ganze Elementen-Gruppe anzuwählen. Zu dieser Spezifität gehören außerdem
noch Attributselektoren und Pseudo-Klassen.
Typ
Am wenigsten schwer wiegen ganze Element-Gruppen, also
Typ-Selektoren. Wird beispielsweise „p“, als Selektor verwendet, gilt das
zunächst für alle Paragraphen, ist also am wenigsten spezifisch. Auch
Pseudo-Elemente zählen in diesem Fall zu dieser Gruppe.
Das Punktesystem der Spezifität
Wie also funktioniert nun das eigentliche Punktesystem?
Für jeden verwendeten Selektor wird ein Punkt in einer der
obgenannten Kategorien vergeben. Man kann sich das so vorstellen:
Würde man beispielsweise einen Style für alle h1-Überschriften
definieren, würde das folgendermaßen gezählt werden:
Die Spezifität für h1 wäre also 0,0,0,1.
Ein weiteres, realistisches, aber schon etwas kniffligeres Beispiel zur
Spezifität:
Dieser Link, der sich in einer unordered list mit der ID „nav-bar“ und einem li-Element mit der Klasse „active“ befindet, hat die Spezifität
0,1,1,3. Somit kann ihm ein anderes Styling verliehen werden, als den anderen
Links in dieser Navigationsleiste („ul#nav-bar
li a“ hat nur eine Spezifität von 0,1,0,3).
Wird ein Wert im HTML-Dokument inline mittels Style-Attribut festgelegt, entspricht das der
höchsten Spezifität. In diesem Beispiel 1,0,0,0.
Ausnahmen
·
Der oben in der tabellarischen Übersicht
erwähnte Universalselektor (*) erhöht die Spezifität NICHT.
·
Die Pseudo-Klasse :not() erhöht die Spezifität
ebenfalls nicht; das übergebene Argument allerdings schon.
Beispiel:
p:not(.myClass) hat eine Spezifität von 0,0,1,1.
·
!important
überschreibt auch inline
Style-Attribute. Allerdings sollte !important
nur äußerst sparsam und wohlüberlegt (und idealerweise gar nicht) eingesetzt
werden.
Links
Kurse von ppedv zum Thema HTML, CSS und Responsive Design gibt es hier.
Die W3C-Spezifikation zur specificity findet sich hier.
Andy Clarke beschreibt specificity in seinem Blog so: