Kapitel 4. Spezifität, Vererbung und die Kaskade
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
In den Kapiteln 2 und 3 wurde gezeigt, wie die Dokumentstruktur und CSS-Selektoren es dir ermöglichen, eine Vielzahl von Stilen auf Elemente anzuwenden. Da du weißt, dass jedes gültige Dokument einen Strukturbaum erzeugt, kannst du Selektoren erstellen, die Elemente auf der Grundlage ihrer Vorgänger, Attribute, Geschwisterelemente und mehr ansprechen. Der Strukturbaum ermöglicht die Funktion von Selektoren und ist auch für einen anderen wichtigen Aspekt von CSS von zentraler Bedeutung: die Vererbung.
Vererbung ist der Mechanismus, durch den einige Eigenschaftswerte von einem Element an ein nachgeordnetes Element weitergegeben werden. Bei der Entscheidung, welche Werte für ein Element gelten sollen, muss ein User Agent nicht nur die Vererbung, sondern auch die Besonderheit der Deklarationen sowie den Ursprung der Deklarationen selbst berücksichtigen. Dieser Abwägungsprozess wird als Kaskade bezeichnet.
Wir werden in diesem Kapitel die Wechselbeziehung zwischen diesen drei Mechanismen - Spezifität, Vererbung und Kaskade - untersuchen. Im Moment lässt sich der Unterschied zwischen den beiden letztgenannten Mechanismen so zusammenfassen: Wenn wir h1 {color: red; color: blue;}
schreiben, wird <h1>
aufgrund der Kaskade blau, und jedes <span>
innerhalb von <h1>
wird aufgrund der Vererbung ebenfalls blau.
Und vor allem: Egal, wie abstrakt die Dinge auch erscheinen mögen, mach weiter! Dein Durchhaltevermögen wird belohnt werden.
Spezifität
Du weißt aus den Kapiteln 2 und 3, dass du Elemente mit einer Vielzahl von Mitteln auswählen kannst. Tatsächlich kann ein und dasselbe Element oft durch zwei oder mehr Regeln ausgewählt werden, jede mit ihrem eigenen Selektor. Betrachten wir die folgenden drei Paare von Regeln. Nehmen wir an, dass jedes Paar auf dasselbe Element passt:
h1
{
color
:
red
;}
body
h1
{
color
:
green
;}
h2
.grape
{
color
:
purple
;}
h2
{
color
:
silver
;}
html
>
body
table
tr
[
id
=
"totals"
]
td
ul
>
li
{
color
:
maroon
;}
li
#answer
{
color
:
navy
;}
Nur eine der beiden Regeln in jedem Paar kann angewendet werden oder "gewinnen", da die übereinstimmenden Elemente jeweils nur eine Farbe haben können. Woher wissen wir, welche gewinnen wird?
Die Antwort liegt in der Spezifität der einzelnen Selektoren. Für jede Regel bewertet der User Agent (d. h. ein Webbrowser) die Spezifität des Selektors und fügt die Spezifität jeder Deklaration in der Regel innerhalb der Kaskadenebene zu, die Vorrang hat. Wenn ein Element zwei oder mehr widersprüchliche Eigenschaftserklärungen hat, setzt sich diejenige mit der höchsten Spezifität durch.
Hinweis
Das ist nicht die ganze Geschichte der Konfliktlösung, die ein bisschen komplizierter ist, als ein einzelner Absatz behandeln kann. Fürs Erste solltest du dir merken, dass die Spezifität eines Selektors nur mit anderen Selektoren verglichen wird, die denselben Ursprung und dieselbe Kaskadenebene haben. Wir werden diese Begriffe und mehr in "Die Kaskade" behandeln .
Die Spezifität eines Selektors wird durch die Komponenten des Selektors selbst bestimmt. Ein Spezifitätswert kann in drei Teilen wie folgt ausgedrückt werden: 0,0,0
. Die tatsächliche Spezifität eines Selektors wird wie folgt bestimmt:
-
Füge für jeden Wert des Attributs ID, der im Selektor angegeben ist,
1,0,0
hinzu. -
Für jeden Klassenattributwert, jede Attributauswahl oder jede Pseudoklasse, die im Selektor angegeben ist, füge
0,1,0
hinzu. -
Füge für jedes Element und Pseudoelement, das im Selektor angegeben ist,
0,0,1
hinzu. -
Die Kombinatoren tragen nichts zur Besonderheit bei.
-
Alles, was innerhalb einer
:where()
Pseudoklasse aufgeführt ist, und der Universalselektor fügen0,0,0
hinzu. (Sie tragen zwar nicht zur Gewichtung der Spezifität bei, passen aber im Gegensatz zu den Kombinatoren zu den Elementen). -
Die Spezifität einer
:is()
,:not()
oder:has()
Pseudoklasse ist gleich der Spezifität des spezifischsten Selektors in ihrem Selektorlistenargument.
Die Selektoren der folgenden Regeln führen zum Beispiel zu den angegebenen Besonderheiten:
h1
{
color
:
red
;}
/* specificity = 0,0,1 */
p
em
{
color
:
purple
;}
/* specificity = 0,0,2 */
.grape
{
color
:
purple
;}
/* specificity = 0,1,0 */
*
.bright
{
color
:
yellow
;}
/* specificity = 0,1,0 */
p
.bright
em
.dark
{
color
:
maroon
;}
/* specificity = 0,2,2 */
#id216
{
color
:
blue
;}
/* specificity = 1,0,0 */
*
:is
(
aside
#warn
,
code
)
{
color
:
red
;}
/* specificity = 1,0,1 */
div
#sidebar
*[
href
]
{
color
:
silver
;}
/* specificity = 1,1,1 */
Wenn ein Element <em>
in diesem Beispiel sowohl auf die zweite als auch auf die fünfte Regel zutrifft, wird dieses Element kastanienbraun sein, weil die sechste Regel spezifischer ist als die zweite.
Achte bei besonders auf den vorletzten Selektor, *:is(aside#warn, code)
. Die Pseudoklasse :is()
gehört zu einer kleinen Gruppe von Pseudoklassen, deren Spezifität dem spezifischsten Selektor in der Selektorenliste entspricht. Hier ist die Selektorenliste aside#warn, code
. Der zusammengesetzte Selektor aside#warn
hat eine Spezifität von 1,0,1
und der Selektor code
hat eine Spezifität von 0,0,1
. Der gesamte Teil des Selektors :is()
wird also auf die Spezifität des Selektors aside#warn
gesetzt.
Kehren wir nun zu den Regelpaaren vom Anfang des Abschnitts zurück und füllen die Besonderheiten aus:
h1
{
color
:
red
;}
/* 0,0,1 */
body
h1
{
color
:
green
;}
/* 0,0,2 (winner)*/
h2
.grape
{
color
:
purple
;}
/* 0,1,1 (winner) */
h2
{
color
:
silver
;}
/* 0,0,1 */
html
>
body
table
tr
[
id
=
"totals"
]
td
ul
>
li
{
color
:
maroon
;}
/* 0,1,7 */
li
#answer
{
color
:
navy
;}
/* 1,0,1
(winner) */
Wir haben in jedem Paar die Gewinnerregel angegeben, weil die Spezifität in jedem Fall höher ist. Beachte, wie sie aufgelistet sind und dass die Reihenfolge der Regeln hier keine Rolle spielt.
Im zweiten Paar gewinnt der Selektor h2.grape
, weil er eine zusätzliche Klasse hat: 0,1,1
gewinnt vor 0,0,1
. Im dritten Paar gewinnt die zweite Regel, weil 1,0,1
vor 0,1,7
gewinnt. Eigentlich würde der Spezifitätswert 0,1,0
vor dem Wert 0,0,13
gewinnen.
Das passiert, weil die Werte von links nach rechts verglichen werden. Eine Besonderheit von 1,0,0
gewinnt über jede Besonderheit, die mit 0
beginnt, egal wie die restlichen Zahlen lauten. So gewinnt 1,0,1
über 0,1,7
, weil 1
an der ersten Stelle des ersten Wertes die 0
an der ersten Stelle des zweiten Wertes übertrifft.
Erklärungen und Besonderheit
Sobald die Spezifität eines Selektors bestimmt wurde, wird der Spezifitätswert auf alle damit verbundenen Deklarationen übertragen. Betrachte diese Regel:
h1
{
color
:
silver
;
background
:
black
;}
Aus Gründen der Spezifizität muss der User Agent die Regel so behandeln, als wäre sie in einzelne Regeln "aufgeteilt". So würde das vorherige Beispiel zu folgendem werden:
h1
{
color
:
silver
;}
h1
{
background
:
black
;}
Beide haben eine Spezifität von 0,0,1
, und das ist der Wert, der jeder Deklaration zugewiesen wird. Der gleiche Aufspaltungsprozess findet auch bei einem gruppierten Selektor statt. Gegeben die Regel,
h1
,
h2
.section
{
color
:
silver
;
background
:
black
;}
behandelt der User Agent es so, als ob es das Folgende wäre:
h1
{
color
:
silver
;}
/* 0,0,1 */
h1
{
background
:
black
;}
/* 0,0,1 */
h2
.section
{
color
:
silver
;}
/* 0,1,1 */
h2
.section
{
background
:
black
;}
/* 0,1,1 */
Das wird wichtig, wenn mehrere Regeln auf dasselbe Element zutreffen und einige der Deklarationen sich überschneiden. Betrachte zum Beispiel diese Regeln:
h1
+
p
{
color
:
black
;
font-style
:
italic
;}
/* 0,0,2 */
p
{
color
:
gray
;
background
:
white
;
font-style
:
normal
;}
/* 0,0,1 */
*
.callout
{
color
:
black
;
background
:
silver
;}
/* 0,1,0 */
Bei Anwendung auf das folgende Markup wird der Inhalt wie in Abbildung 4-1 gezeigt dargestellt:
<h1>
Greetings!</h1>
<p
class=
"callout"
>
It's
a
fine
way
to
start
a
day,
don't
you
think?
</p>
<p>
There
are
many
ways
to
greet
a
person,
but
the
words
are
not
as
important
as
the
act
of
greeting
itself.
</p>
<h1>
Salutations!</h1>
<p>
There
is
nothing
finer
than
a
hearty
welcome
from
one's
neighbor.
</p>
<p
class=
"callout"
>
Although
a
steaming
pot
of
fresh-made
jambalaya
runs
a
close
second.
</p>
In jedem Fall bestimmt der User Agent, welche Regeln auf ein bestimmtes Element passen, berechnet alle zugehörigen Deklarationen und ihre Besonderheiten, bestimmt, welche Regeln sich durchsetzen, und wendet dann die Gewinner auf das Element an, um das gestylte Ergebnis zu erhalten. Diese Vorgänge müssen für jedes Element, jeden Selektor und jede Deklaration durchgeführt werden. Zum Glück macht der User Agent das alles automatisch und fast augenblicklich. Dieses Verhalten ist ein wichtiger Bestandteil der Kaskade, die wir später in diesem Kapitel besprechen werden.
Auflösen von Mehrfachtreffern
Wenn ein Element von mehr als einem Selektor in einem gruppierten Selektor gefunden wird, wird der spezifischste Selektor verwendet. Betrachte das folgende CSS:
li
,
/* 0,0,1 */
.quirky
,
/* 0,1,0 */
#friendly
,
/* 1,0,0 */
li
.happy.happy.happy
#friendly
{
/* 1,3,1 */
color
:
blue
;
}
Hier haben wir eine Regel mit einem gruppierten Selektor, und jeder der einzelnen Selektoren hat eine ganz andere Spezifität. Nehmen wir nun an, wir finden dies in unserem HTML:
<li
class=
"happy quirky"
id=
"friendly"
>
Thiswill
be
blue.
</li>
Jeder der Selektoren im gruppierten Selektor gilt für das Listenelement! Welcher wird für die Spezifität verwendet? Der spezifischste. In diesem Beispiel wird der blaue Selektor mit einer Spezifität von 1,3,1
angewendet.
Du hast vielleicht bemerkt, dass wir den Klassennamen happy
in einem der Selektoren dreimal wiederholt haben. Dies ist ein kleiner Hack, der mit Klassen, Attributen, Pseudoklassen und sogar ID-Selektoren verwendet werden kann, um die Spezifität zu erhöhen. Sei aber vorsichtig damit, denn eine künstlich aufgeblähte Spezifität kann in Zukunft zu Problemen führen: Du möchtest diese Regel vielleicht mit einer anderen überschreiben, und für diese Regel müssen dann noch mehr Klassen miteinander verknüpft werden.
Zeroed Selector Spezifität
Der Universalselektor trägt nicht zur Spezifizität bei. Er hat eine Spezifität von 0,0,0
, was etwas anderes ist, als keine Spezifität zu haben (wie wir in "Vererbung" besprechen werden ). Mit den folgenden zwei Regeln ist ein Absatz, der von <div>
abstammt, schwarz, aber alle anderen Elemente sind grau:
div
p
{
color
:
black
;}
/* 0,0,2 */
*
{
color
:
gray
;}
/* 0,0,0 */
Das bedeutet, dass die Spezifität eines Selektors, der einen Universalselektor zusammen mit anderen Selektoren enthält, durch das Vorhandensein des Universalselektors nicht verändert wird. Die folgenden zwei Selektoren haben genau dieselbe Spezifität:
div
p
/* 0,0,2 */
body
*
strong
/* 0,0,2 */
Das Gleiche gilt für die Pseudoklasse :where()
, unabhängig davon, welche Selektoren in ihrer Selektorenliste stehen. Somit hat :where(aside#warn, code)
eine Spezifität von 0,0,0
.
Die Kombinatoren einschließlich ~
, >
, +
und das Leerzeichen haben überhaupt keine Spezifität - nicht einmal null Spezifität. Daher haben sie keinen Einfluss auf die Gesamtspezifität eines Selektors.
Spezifität von ID- und Attributselektoren
Es ist wichtig, den Unterschied in der Spezifität zwischen einem ID-Selektor und einem Attributselektor zu beachten, der auf ein id
Attribut abzielt. Wenn wir zum dritten Regelpaar im Beispielcode zurückkehren, finden wir Folgendes:
html
>
body
table
tr
[
id
=
"totals"
]
td
ul
>
li
{
color
:
maroon
;}
/* 0,1,7 */
li
#answer
{
color
:
navy
;}
/* 1,0,1 (wins) */
Der ID-Selektor (#answer
) in der zweiten Regel trägt 1,0,0
zur Gesamtspezifität des Selektors bei. In der ersten Regel hingegen trägt der Attributselektor ([id="totals"]
) mit 0,1,0
zur Gesamtspezifität bei. Mit den folgenden Regeln wird das Element mit einem id
von meadow
also grün sein:
#meadow
{
color
:
green
;}
/* 1,0,0 */
*[
id
=
"meadow"
]
{
color
:
red
;}
/* 0,1,0 */
Bedeutung
Manchmal ist eine Erklärung so wichtig, dass sie alle anderen Überlegungen überwiegt. CSS nennt diese wichtigen Deklarationen (aus hoffentlich offensichtlichen Gründen) und ermöglicht es dir, sie zu markieren, indem du das Flag !important
direkt vor dem abschließenden Semikolon in einer Deklaration einfügst:
p
.dark
{
color
:
#333
!important
;
background
:
white
;}
Hier ist der Farbwert von #333
mit dem Flag !important
markiert, der Hintergrundwert von white
hingegen nicht. Wenn du beide Deklarationen als wichtig kennzeichnen möchtest, braucht jede Deklaration ihr eigenes !important
Flag:
p
.dark
{
color
:
#333
!important
;
background
:
white
!important
;}
Du musst das !important
Flag richtig setzen, sonst kann die Erklärung ungültig werden:
!important
Das Flag steht immer am Ende einer Deklaration, direkt vor dem Semikolon. Diese Platzierung ist besonders wichtig, wenn es sich um Eigenschaften handelt, die Werte mit mehreren Schlüsselwörtern zulassen, wie z. B. font
:
p
.light
{
color
:
yellow
;
font
:
smaller
Times
,
serif
!important
;}
Wenn !important
an einer anderen Stelle in der font
Deklaration platziert wäre, würde wahrscheinlich die gesamte Deklaration ungültig und keiner der Stile würde angewendet.
Hinweis
Wir sind uns bewusst, dass die Syntax dieses Tokens für diejenigen unter euch, die aus der Programmierung kommen, instinktiv "nicht wichtig" bedeutet. Aus welchem Grund auch immer, wurde der Knall (!
) als Trennzeichen für wichtige Flaggen gewählt, und er bedeutet in CSS nicht "nicht", egal wie viele andere Sprachen ihm genau diese Bedeutung geben. Diese Assoziation ist unglücklich, aber wir müssen uns damit abfinden.
Deklarationen, die mit !important
gekennzeichnet sind, haben keinen speziellen Spezifitätswert, sondern werden getrennt von unwichtigen Deklarationen betrachtet. Alle !important
Deklarationen werden in einer Gruppe zusammengefasst, und Spezifitätskonflikte werden innerhalb dieser Gruppe gelöst. Ebenso werden alle unwichtigen Deklarationen als Gruppe betrachtet, wobei Konflikte innerhalb der unwichtigen Gruppe wie oben beschrieben gelöst werden. Wenn also eine wichtige und eine unwichtige Deklaration miteinander kollidieren, gewinnt immer die wichtige Deklaration (es sei denn, der User Agent oder der Benutzer haben dieselbe Eigenschaft als wichtig deklariert, was du später im Kapitel sehen wirst).
Abbildung 4-2 veranschaulicht das Ergebnis der folgenden Regeln und des Markup-Fragments:
h1
{
font-style
:
italic
;
color
:
gray
!important
;}
.title
{
color
:
black
;
background
:
silver
;}
*
{
background
:
black
!important
;}
<h1
class=
"title"
>
NightWing</h1>
Warnung
Die Verwendung von !important
in deinem CSS ist generell eine schlechte Praxis und wird nur selten benötigt. Wenn du zu !important
greifst, halte inne und suche nach anderen Möglichkeiten, um das gleiche Ergebnis zu erzielen, ohne!important
zu verwenden. Kaskadenebenen sind eine solche Möglichkeit; siehe "Sortieren nach Kaskadenebenen" für weitere Informationen.
Vererbung
Ein weiteres wichtiges Konzept, um zu verstehen, wie Stile auf Elemente angewendet werden, ist die Vererbung. Vererbung ist der Mechanismus, durch den bestimmte Stile nicht nur auf ein bestimmtes Element, sondern auch auf seine Nachkommen angewendet werden. Wenn zum Beispiel eine Farbe auf ein <h1>
Element angewendet wird, wird diese Farbe auf den gesamten Text innerhalb des <h1>
Elements angewendet, auch auf den Text in den untergeordneten Elementen dieses <h1>
Elements:
h1
{
color
:
gray
;}
<h1>
Meerkat
<em>
Central</em></h1>
Sowohl der normale <h1>
Text als auch der <em>
Text sind grau eingefärbt, weil das <em>
Element den Wert von color
von <h1>
erbt. Wenn Eigenschaftswerte nicht an nachgeordnete Elemente vererbt werden könnten, wäre der <em>
Text schwarz und nicht grau, und wir müssten die Elemente separat einfärben.
Betrachte eine ungeordnete Liste. Nehmen wir an, wir wenden einen Stil von color: gray;
für <ul>
an:
ul
{
color
:
gray
;}
Wir gehen davon aus, dass die Formatvorlage, die auf <ul>
angewendet wird, auch auf die Listenelemente und den Inhalt dieser Listenelemente angewendet wird, einschließlich der Markierung (d. h. das Aufzählungszeichen neben jedem Listenelement). Dank der Vererbung passiert genau das, wie in Abbildung 4-3 zu sehen ist.
Es ist einfacher zu sehen, wie Vererbung funktioniert, wenn du ein Baumdiagramm eines Dokuments betrachtest. Abbildung 4-4 zeigt das Baumdiagramm für ein Dokument, das dem in Abbildung 4-3 gezeigten sehr einfachen Dokument ähnelt.
Wenn die Deklaration color: gray;
auf das Element <ul>
angewendet wird, übernimmt dieses Element die Deklaration. Der Wert wird dann in der Baumstruktur an die nachgeordneten Elemente weitergegeben, bis keine nachgeordneten Elemente mehr übrig sind, die den Wert erben können. Werte werden niemals nach oben weitergegeben; ein Element gibt niemals Werte an seine Vorfahren weiter.
Hinweis
Die Regel für die Weitergabe nach oben in HTML hat eine bemerkenswerte Ausnahme: Hintergrundstile, die auf das <body>
Element angewendet werden, können an das <html>
Element weitergegeben werden, das das Wurzelelement des Dokuments ist und daher seine Leinwand definiert. Dies geschieht nur, wenn das Element <body>
einen definierten Hintergrund hat und das Element <html>
nicht. Einige andere Eigenschaften haben dieses Body-to-Root-Verhalten, wie z. B. overflow
, aber es passiert nur mit dem <body>
Element. Bei keinem anderen Element besteht die Gefahr, dass es Eigenschaften von einem Nachfahren erbt.
Vererbung gehört zu den Dingen in CSS, die so grundlegend sind, dass du fast nie darüber nachdenkst, es sei denn, du musst es tun. Trotzdem solltest du ein paar Dinge beachten.
Zunächst ist zu beachten, dass viele Eigenschaften von nicht vererbt werden - in der Regel, um unerwünschte Ergebnisse zu vermeiden. Zum Beispiel wird die Eigenschaft border
(mit der die Ränder von Elementen festgelegt werden) nicht vererbt. Ein kurzer Blick auf Abbildung 4-5 zeigt, warum das so ist. Würden die Rahmen vererbt, würden die Dokumente viel unübersichtlicher werden - es sei denn, der Autor macht sich die Mühe, die vererbten Rahmen zu deaktivieren.
Aus demselben Grund werden die meisten Eigenschaften des Box-Modells - wie Ränder, Auffüllungen, Hintergründe und Umrandungen - nicht vererbt. Schließlich möchtest du wahrscheinlich nicht, dass alle Links in einem Absatz einen linken Rand von 30 Pixeln von ihrem übergeordneten Element erben!
Zweitens haben vererbte Werte überhaupt keine Spezifität, nicht einmal null Spezifität. Das scheint eine akademische Unterscheidung zu sein, bis du dich mit den Konsequenzen der fehlenden vererbten Spezifität auseinandersetzt. Betrachte die folgenden Regeln und das Markup-Fragment und vergleiche sie mit dem in Abbildung 4-6 gezeigten Ergebnis:
*
{
color
:
gray
;}
h1
#page-title
{
color
:
black
;}
<h1
id=
"page-title"
>
Meerkat
<em>
Central</em></h1>
<p>
Welcome
to
the
best
place
on
the
web
for
meerkat
information!
</p>
Da der universelle Selektor für alle Elemente gilt und keine Spezifität hat, gewinnt der Wert der Farbdeklaration gray
gegenüber dem geerbten Wert black
, der überhaupt keine Spezifität hat. (Jetzt verstehst du vielleicht, warum wir :where()
und den universellen Selektor mit 0,0,0
Spezifität aufgeführt haben: Sie haben kein Gewicht, passen aber zu Elementen.) Deshalb wird das Element <em>
nicht schwarz, sondern grau dargestellt.
Dieses Beispiel veranschaulicht anschaulich eines der potenziellen Probleme bei der wahllosen Verwendung des Universalselektors. Da er auf jedes beliebige Element oder Pseudoelement passen kann, führt der Universalselektor oft dazu, dass die Vererbung kurzgeschlossen wird. Das lässt sich zwar umgehen, aber in der Regel ist es sinnvoller, das Problem von vornherein zu vermeiden, indem man den Universalselektor nicht wahllos einsetzt.
Das völlige Fehlen einer Spezifität für vererbte Werte ist kein trivialer Punkt. Nehmen wir zum Beispiel an, dass ein Stylesheet so geschrieben wurde, dass der gesamte Text in einer Symbolleiste weiß auf schwarz sein soll:
#toolbar
{
color
:
white
;
background
:
black
;}
Das funktioniert so lange, wie das Element mit einem id
von toolbar
nur einfachen Text enthält. Wenn der Text in diesem Element jedoch ausschließlich aus Hyperlinks besteht (a
Elemente), werden die Stile des User Agents für Hyperlinks übernommen. In einem Webbrowser bedeutet das, dass sie wahrscheinlich blau eingefärbt werden, da das interne Stylesheet des Browsers wahrscheinlich einen Eintrag wie diesen enthält:
a
:link
{
color
:
blue
;}
Um dieses Problem zu lösen, musst du etwas wie folgt deklarieren:
#toolbar
{
color
:
white
;
background
:
black
;}
#toolbar
a
:any-link
{
color
:
white
;}
Wenn du eine Regel direkt auf die a
Elemente in der Symbolleiste ausrichtest, erhältst du das in Abbildung 4-7 gezeigte Ergebnis.
Eine andere Möglichkeit, das gleiche Ergebnis zu erzielen, ist die Verwendung des Wertes inherit
, der im nächsten Kapitel behandelt wird. Wir können das vorherige Beispiel wie folgt abändern:
#toolbar
{
color
:
white
;
background
:
black
;}
#toolbar
a
:link
{
color
:
inherit
;}
Dies führt auch zu dem in Abbildung 4-7 gezeigten Ergebnis, da der Wert von color
dank einer zugewiesenen Regel, deren Selektor eine Spezifität hat, explizit vererbt wird.
Die Kaskade
In diesem Kapitel haben wir ein wichtiges Thema umschifft: Was passiert, wenn zwei gleichwertige Regeln auf dasselbe Element zutreffen? Wie löst der Browser den Konflikt auf? Betrachten wir zum Beispiel die folgenden Regeln:
h1
{
color
:
red
;}
h1
{
color
:
blue
;}
Welche ist besser? Beide haben eine Spezifität von 0,0,1
, also haben sie das gleiche Gewicht und sollten beide gelten. Das kann nicht der Fall sein, weil das Element nicht gleichzeitig rot und blau sein kann. Welches wird es also sein?
Endlich kommt der Name Cascading Style Sheets ins Spiel: CSS basiert auf einer Methode, bei der Stile kaskadiert werden, was durch die Kombination von Vererbung und Spezifität mit einigen wenigen Regeln möglich ist. Die Kaskadenregeln für CSS lauten wie folgt:
-
Finde alle Regeln, die einen Selektor enthalten, der auf ein bestimmtes Element passt.
-
Sortiert alle Deklarationen, die für das angegebene Element gelten, nach expliziter Gewichtung.
-
Sortiert alle Deklarationen, die für das angegebene Element gelten, nach Herkunft. Es gibt drei grundlegende Ursprünge: Autor, Leser und User Agent. Unter normalen Umständen haben die Stile des Autors (d. h. deine Stile als Autor der Seite) Vorrang vor den Stilen des Lesers, und sowohl die Stile des Autors als auch die des Lesers setzen die Standardstile des Benutzeragenten außer Kraft. Bei Regeln, die mit
!important
gekennzeichnet sind, ist dies umgekehrt: Die Stile des User Agents haben Vorrang vor den Stilen des Autors und beide haben Vorrang vor den Stilen des Lesers. -
Sortiert alle Deklarationen, die für das angegebene Element gelten, nach dem Encapsulation Context. Wenn ein Stil z. B. über ein Schatten-DOM zugewiesen wird, hat er einen Kapselungskontext für alle Elemente innerhalb dieses Schatten-DOMs und gilt nicht für Elemente außerhalb des Schatten-DOMs. So können gekapselte Stile Stile überschreiben, die von außerhalb des Shadow DOM geerbt werden.
-
Sortiere alle Deklarationen danach, ob sie mit einem Element verbunden sind. Stile, die über ein
style
-Attribut zugewiesen werden, sind elementgebunden. Stile, die über ein externes oder eingebettetes Stylesheet zugewiesen werden, sind es nicht. -
Sortiere alle Deklarationen nach Kaskadenebene. Für normalgewichtige Stile gilt: Je später eine Kaskadenebene zum ersten Mal im CSS auftaucht, desto höher ist der Vorrang. Stile ohne Ebene werden als Teil einer "Standard"-Pseudoebene betrachtet, die einen höheren Vorrang hat als Stile in explizit erstellten Ebenen. Je früher eine Kaskadenebene im CSS auftaucht, desto höher ist der Vorrang für wichtige Stile, und alle wichtigen Stile in explizit erstellten Ebenen haben Vorrang vor Stilen in der Standardebene, egal ob wichtig oder nicht. Kaskadenebenen können in jedem Ursprung erscheinen.
-
Sortiert alle Deklarationen, die auf das angegebene Element zutreffen, nach ihrer Spezifität. Die Elemente mit einer höheren Spezifität haben mehr Gewicht als die mit einer niedrigeren Spezifität.
-
Sortiert alle Deklarationen, die für das angegebene Element gelten, nach der Reihenfolge ihres Erscheinens. Je später eine Deklaration im Stylesheet oder Dokument erscheint, desto mehr Gewicht erhält sie. Deklarationen, die in einem importierten Stylesheet erscheinen, werden vor allen Deklarationen innerhalb des Stylesheets, das sie importiert, berücksichtigt.
Um zu verstehen, wie das alles funktioniert, betrachten wir Beispiele, die einige der Kaskadenregeln veranschaulichen.
Sortierung nach Wichtigkeit und Herkunft
Wenn zwei Regeln für ein Element gelten und eine davon mit !important
markiert ist,hat die wichtige RegelVorrang:
p
{
color
:
gray
!important
;}
<p
style=
"color: black;"
>
Well,
<em>
hello</em>
there!
</p>
Obwohl im Attribut style
des Absatzes eine Farbe zugewiesen ist, setzt sich die Regel !important
durch, und der Absatz ist grau. Das liegt daran, dass die Sortierung nach !important
einen höheren Vorrang hat als die Sortierung nach den mit dem Element verbundenen Stilen (style=""
). Das Grau wird auch an das Element <em>
vererbt.
Wenn !important
in dieser Situation zum Inline-Stil hinzugefügt wird, ist er der Gewinner. In diesem Fall ist der Absatz (und sein untergeordnetes Element) schwarz:
p
{
color
:
gray
!important
;}
<p
style=
"color: black !important;"
>
Well,
<em>
hello</em>
there!
</p>
Wenn die Bedeutung gleich ist, wird der Ursprung einer Regel berücksichtigt. Wenn ein Element sowohl im Stylesheet des Autors als auch im Stylesheet des Lesers mit normalen Stilen übereinstimmt, werden die Stile des Autors verwendet. Nehmen wir zum Beispiel an, dass die folgenden Stile aus den angegebenen Ursprüngen stammen:
p
em
{
color
:
black
;}
/* author's stylesheet */
p
em
{
color
:
yellow
;}
/* reader's stylesheet */
In diesem Fall wird hervorgehobener Text innerhalb von Absätzen nicht gelb, sondern schwarz gefärbt, weil die Autorenstile über die Leserstile siegen. Wenn jedoch beide Regeln markiert sind!important
markiert sind, ändert sich die Situation:
p
em
{
color
:
black
!important
;}
/* author's stylesheet */
p
em
{
color
:
yellow
!important
;}
/* reader's stylesheet */
Jetzt wird der hervorgehobene Text in Absätzen gelb und nicht mehr schwarz sein.
Die Standardstile des User Agents, die oft von den Benutzereinstellungen beeinflusst werden, werden in diesem Schritt berücksichtigt. Die Standardstildeklarationen haben den geringsten Einfluss. Wenn also eine vom Autor festgelegte Regel für Anker gilt (z. B. die Erklärung, dass sie white
sind), dann setzt diese Regel die Standardeinstellungen des User Agents außer Kraft.
Zusammenfassend lässt sich sagen, dass es in CSS acht grundlegende Ebenen für den Vorrang von Deklarationen gibt. In der Reihenfolge vom höchsten bis zum niedrigsten Vorrang sind dies die folgenden:
-
Übergangserklärungen (siehe Kapitel 18)
-
Wichtige Erklärungen zum Benutzeragenten
-
Wichtige Erklärungen der Leser
-
Wichtige Erklärungen des Autors
-
Animationsdeklarationen (siehe Kapitel 19)
-
Autor normale Erklärungen
-
Leser normale Erklärungen
-
Erklärungen zum Benutzeragenten
Ein Übergangsstil setzt also alle anderen Regeln außer Kraft, unabhängig davon, ob diese anderen Regeln mit !important
gekennzeichnet sind oder woher die Regeln stammen.
Sortieren nach Elementanhang
Stile können mit einem Markup-Attribut wie style
an ein Element angehängt werden. Diese Stile werden als elementgebundene Stile bezeichnet und werden nur durch Überlegungen zu Herkunft und Gewicht aufgewogen.
Um dies zu verstehen, betrachte die folgende Regel und das folgende Markup-Fragment:
h1
{
color
:
red
;}
<h1
style=
"color: green;"
>
TheMeadow
Party
</h1>
Da die Regel auf das Element <h1>
angewendet wird, würdest du wahrscheinlich trotzdem erwarten, dass der Text von <h1>
grün ist. Das liegt daran, dass jede Inline-Deklaration mit einem Element verbunden ist und daher ein höheres Gewicht hat als Stile, die nicht mit einem Element verbunden sind, wie die Regel color: red
.
Das bedeutet, dass auch Elemente mit id
Attributen, die einer Regel entsprechen, der Inline-Stildeklaration gehorchen. Ändern wir das vorherige Beispiel, um ein id
einzufügen:
h1
#meadow
{
color
:
red
;}
<h1
id=
"meadow"
style=
"color: green;"
>
TheMeadow
Party
</h1>
Dank der Gewichtung der Inline-Deklaration wird der Text des Elements <h1>
weiterhin grün sein.
Erinnere dich daran, dass Inline-Stile im Allgemeinen eine schlechte Praxis sind, also versuche, sie möglichst nicht zu verwenden.
Sortieren nach Kaskadenebene
MitKaskadenebenen können die Autoren von Stile so gruppieren, dass sie innerhalb der Kaskade eine gemeinsame Vorrangstufe haben. Das klingt vielleicht wie !important
; in mancher Hinsicht sind sie ähnlich, aber in anderen sehr unterschiedlich. Es ist einfacher, dies zu demonstrieren als es zu beschreiben. Die Möglichkeit, Kaskadenebenen zu erstellen, bedeutet, dass Autorinnen und Autoren verschiedene Anforderungen, wie z. B. die Anforderungen einer Komponentenbibliothek, mit den Anforderungen einer bestimmten Seite oder eines Teils einer Webanwendung abgleichen können.
Hinweis
Kaskadenebenen wurden Ende 2021 in CSS eingeführt und werden daher nur von Browsern unterstützt, die ab diesem Zeitpunkt veröffentlicht wurden.
Wenn widersprüchliche Deklarationen auf ein Element zutreffen und alle dasselbe explizite Gewicht und denselben Ursprung haben und keines der Elemente angehängt ist, werden sie als Nächstes nach Kaskadenebene sortiert. Die Rangfolge der Ebenen wird durch die Reihenfolge festgelegt, in der die Ebenen zuerst deklariert oder verwendet werden, wobei später deklarierte Ebenen Vorrang vor früher deklarierten Ebenen für normale Stile haben. Betrachte das Folgende:
@layer
site
{
h1
{
color
:
red
;}
}
@layer
page
{
h1
{
color
:
blue
;}
}
Diese <h1>
Elemente werden blau eingefärbt. Das liegt daran, dass die Ebene page
im CSS später kommt als die Ebene site
und daher einen höheren Stellenwert hat.
Jeder Stil, der nicht Teil einer benannten Kaskadenebene ist, wird einer impliziten "Standard"-Ebene zugewiesen, die für unwichtige Regeln einen höheren Vorrang hat als jede benannte Ebene. Nehmen wir an, wir ändern das vorherige Beispiel wie folgt ab:
h1
{
color
:
maroon
;}
@layer
site
{
h1
{
color
:
red
;}
}
@layer
page
{
h1
{
color
:
blue
;}
}
Die Elemente von <h1>
werden nun kastanienbraun sein, da die implizite "Standard"-Ebene, zu der h1 {color: maroon;}
gehört, einen höheren Vorrang hat als jede benannte Ebene.
Du kannst auch eine bestimmte Rangfolge für benannte Kaskadenebenen festlegen. Betrachte das folgende CSS:
@layer
site
,
page
;
@layer
page
{
h1
{
color
:
blue
;}
}
@layer
site
{
h1
{
color
:
red
;}
}
In der ersten Zeile wird die Rangfolge der Ebenen festgelegt: Bei normalgewichtigen Regeln, wie im Beispiel gezeigt, wird der Ebene page
eine höhere Priorität eingeräumt als der Ebene site
. In diesem Fall sind die Elemente von <h1>
blau, weil bei der Sortierung der Ebenen page
eine höhere Priorität hat als site
. Bei Regeln, die mit einer wichtigen Markierung versehen sind, wird die Rangfolge umgedreht. Wären also beide Regeln mit !important
gekennzeichnet, würde sich die Rangfolge umkehren und die Elemente von <h1>
wären rot.
Lass uns ein bisschen mehr darüber reden, wie Kaskadenebenen speziell funktionieren, vor allem, weil sie so neu in CSS sind. Nehmen wir an, du möchtest drei Ebenen definieren: eine für die grundlegenden Stile der Website, eine für einzelne Seitenstile und eine für eine Komponentenbibliothek, deren Stile aus einem externen Stylesheet importiert werden. Das CSS könnte wie folgt aussehen:
@layer site, page;
@import url(/assets/css/components.css) layer(components);
Bei dieser Reihenfolge haben normalgewichtige components
Stile Vorrang vor page
und site
normalgewichtigen Stilen, und normalgewichtige page
Stile haben nur Vorrang vor site
normalgewichtigen Stilen. Umgekehrt haben wichtige site
Stile Vorrang vor allen page
und components
Stilen, egal ob sie wichtig oder normalgewichtig sind, und page
wichtige Stile haben Vorrang vor allen components
Stilen.
Hier ist ein kleines Beispiel dafür, wie die Schichten verwaltet werden können:
@layer
site
,
component
,
page
;
@import
url(/c/lib/core.css)
layer
(
component
);
@import
url(/c/lib/widgets.css)
layer
(
component
);
@import
url(/c/site.css)
layer
(
site
);
@layer
page
{
h1
{
color
:
maroon
;}
p
{
margin-top
:
0
;}
}
@layer
site
{
body
{
font-size
:
1.1rem
;}
h1
{
color
:
orange
;}
p
{
margin-top
:
0.5em
;}
}
p
{
margin-top
:
1em
;}
In diesem Beispiel gibt es drei importierte Stylesheets, von denen eines der Ebene site
und zwei der Ebene component
zugewiesen sind. Dann werden einige Regeln der Ebene page
zugewiesen, und ein paar Regeln werden in der Ebene site
platziert. Die Regeln im Block @layer site {}
werden mit den Regeln aus /c/site.css
zu einer einzigen Ebene site
zusammengefasst.
Danach gibt es eine Regel außerhalb der expliziten Kaskadenebenen, d. h. sie ist Teil der impliziten "Standardebene". Die Regeln in dieser Standardebene setzen die Stile der anderen Ebenen außer Kraft. Mit dem gezeigten Code haben die Absätze also einen oberen Rand von 1em
.
Zuvor legt jedoch eine Direktive die Rangfolge der benannten Ebenen fest: page
hat Vorrang vor component
und site
, und component
hat Vorrang vor site
. Hier siehst du, wie diese verschiedenen Regeln in der Kaskade gruppiert sind, mit Kommentaren, die ihre Platzierung in der Sortierung beschreiben:
/* 'site' layer is the lowest weighted */
@import
url(/c/site.css)
layer
(
site
);
@layer
site
{
body
{
font-size
:
1.1rem
;}
h1
{
color
:
orange
;}
p
{
margin-top
:
0.5em
;}
}
/* 'component' layer is the next-lowest weighted */
@import
url(/c/lib/core.css)
layer
(
component
);
@import
url(/c/lib/widgets.css)
layer
(
component
);
/* 'page' layer is the next-highest weighted */
@layer
page
{
h1
{
color
:
maroon
;}
p
{
margin-top
:
0
;}
}
/* the implicit layer is the highest weighted */
p
{
margin-top
:
1em
;}
Wie du siehst, wird eine Ebene umso stärker gewichtet, je weiter hinten sie in der Reihenfolge der Ebenen steht, die der Sortieralgorithmus der Kaskade anordnet.
Um das klarzustellen: Kaskadenebenen müssen nicht benannt werden. Durch die Benennung wird die Reihenfolge der Ebenen klarer, und es ist möglich, der Ebene Stile hinzuzufügen. Hier sind einige Beispiele für die Verwendung unbenannter Kaskadenebenen:
@import
url(base.css)
layer
;
p
{
margin-top
:
1em
;}
@layer
{
h1
{
color
:
maroon
;}
body
p
{
margin-top
:
0
;}
}
In diesem Fall werden die aus base.css importierten Regeln einer unbenannten Ebene zugewiesen. Auch wenn diese Ebene eigentlich keinen Namen hat, nennen wir sie einfach CL1. Dann setzt eine Regel außerhalb der Ebenen die oberen Absatzränder auf 1em
. Schließlich gibt es noch einen unbenannten Ebenenblock mit ein paar Regeln, den wir uns als CL2 vorstellen.
Wir haben jetzt also Regeln in drei Schichten: CL1, CL2 und die implizite Ebene. Und das ist die Reihenfolge, in der sie betrachtet werden. Wenn also normale Regeln miteinander in Konflikt stehen, gewinnen die Regeln in der impliziten Standardschicht (die in der Reihenfolge an letzter Stelle steht) vor den Regeln in den anderen beiden Schichten, und die Regeln in CL2 gewinnen vor den Regeln in CL1.
Zumindest ist das bei normalgewichtigen Regeln der Fall. Bei den Regeln von !important
wird die Rangfolge umgedreht, so dass die Regeln in CL1 über wichtige Regeln in den anderen beiden Schichten siegen, und wichtige Regeln in CL2 über wichtige Regeln in der impliziten Schicht. Seltsam, aber wahr!
Die Sortierung nach der Reihenfolge wird in Kürze wieder auftauchen, aber zuerst wollen wir die Spezifität in die Kaskade bringen.
Sortieren nach Spezifität
Wenn für ein Element widersprüchliche Deklarationen gelten und diese Deklarationen alle dasselbe explizite Gewicht, denselben Ursprung, dieselbe Elementzugehörigkeit (oder deren Fehlen) und dieselbe Kaskadenebene haben, werden sie nach ihrer Spezifität sortiert. Die spezifischste Erklärung gewinnt, etwa so:
@layer
page
{
p
#bright#bright#bright
{
color
:
grey
;}
}
p
#bright
{
color
:
silver
;}
p
{
color
:
black
;}
<p
id=
"bright"
>
Well,hello
there!
</p>
Aufgrund dieser Regeln wird der Text des Absatzes silbern sein, wie in Abbildung 4-8 dargestellt. Warum? Weil die Besonderheit von p#bright
(1,0,1
) die Besonderheit von p
(0,0,1)
) aufhebt, obwohl die letztere Regel später im Stylesheet steht. Die Stile der Ebene page
werden nicht einmal miteinander verglichen, obwohl sie den stärksten Selektor (3,0,1
) haben. Nur die Deklarationen aus der Ebene mit dem Vorrang werden miteinander verglichen.
Erinnere dich daran, dass diese Regel nur gilt, wenn die Regeln Teil der gleichen Kaskadenebene sind. Ist dies nicht der Fall, spielt die Spezifität keine Rolle: Ein 0,0,1
Selektor in der impliziten Ebene wird über jede unwichtige Regel in einer explizit erstellten Kaskadenebene siegen, egal wie hoch die Spezifität der letzteren ist.
Sortieren nach Reihenfolge
Wenn schließlich zwei Regeln genau dasselbe explizite Gewicht, denselben Ursprung, dieselbe Elementanbindung, dieselbe Kaskadenebene und dieselbe Spezifität haben, dann gewinnt diejenige, die später im Stylesheet erscheint, ähnlich wie die Kaskadenebenen in der Reihenfolge sortiert werden, so dass spätere Ebenen über frühere Ebenen gewinnen.
Kehren wir zu einem früheren Beispiel zurück, wo wir die folgenden zwei Regeln im Stylesheet des Dokuments finden:
body
h1
{
color
:
red
;}
html
h1
{
color
:
blue
;}
In diesem Fall wird der Wert von color
für alle <h1>
Elemente im Dokument blue
und nicht red
sein. Das liegt daran, dass die beiden Regeln in Bezug auf das explizite Gewicht und den Ursprung miteinander verbunden sind, sich in der gleichen Kaskadenebene befinden und die Selektoren die gleiche Spezifität haben, so dass die zuletzt deklarierte der Gewinner ist. Es spielt keine Rolle, wie nah die Elemente im Dokumentenbaum beieinander liegen; auch wenn <body>
und <h1>
näher beieinander liegen als <html>
und <h1>
, gewinnt die letztere. Das Einzige, was zählt (wenn der Ursprung, die Kaskadenebene, die Ebene und die Spezifität gleich sind), ist die Reihenfolge, in der die Regeln im CSS erscheinen.
Was passiert also, wenn Regeln aus völlig unterschiedlichen Stylesheets miteinander in Konflikt geraten? Nehmen wir zum Beispiel Folgendes an:
@import
url(basic.css)
;
h1
{
color
:
blue
;}
Was ist, wenn h1 {color: red;}
in basic.css vorkommt? Da in diesem Fall keine Kaskadenebenen im Spiel sind, wird der gesamte Inhalt von basic.css so behandelt, als ob er an der Stelle, an der @import
vorkommt, in das Stylesheet eingefügt wurde. Das bedeutet, dass jede Regel, die im Stylesheet des Dokuments enthalten ist, später auftaucht als die von @import
. Bei Gleichstand in Bezug auf explizite Gewichtung und Spezifität enthält das Stylesheet des Dokuments den Gewinner. Betrachte dasFolgende:
p
em
{
color
:
purple
;}
/* from imported stylesheet */
p
em
{
color
:
gray
;}
/* rule contained within the document */
In diesem Fall gewinnt die zweite Regel gegenüber der importierten Regel, weil sie als letzte angegeben wurde und beide in der impliziten Kaskadenebene liegen.
Ordnung Sortierung ist der Grund für die oft empfohlene Ordnung der Linkstile. Die Empfehlung lautet, dass du deine Linkstile in der Reihenfolge link
, visited
, focus
, hover
, active
, oder LVFHA schreibst, etwa so:
a
:link
{
color
:
blue
;}
a
:visited
{
color
:
purple
;}
a
:focus
{
color
:
green
;}
a
:hover
{
color
:
red
;}
a
:active
{
color
:
orange
;}
Dank der Informationen in diesem Kapitel weißt du jetzt, dass die Spezifität all dieser Selektoren die gleiche ist: 0,1,1
. Da sie alle dasselbe explizite Gewicht, denselben Ursprung und dieselbe Spezifität haben, wird der letzte, der auf ein Element passt, gewinnen. Ein nicht besuchter Link, der angeklickt oder anderweitig aktiviert wird, z. B. über die Tastatur, wird von vier Regeln erkannt -:link
, :focus
, :hover
und :active
-, sodass die letzte dieser vier Regeln den Zuschlag erhält. Angesichts der LVFHA-Reihenfolge wird :active
gewinnen, was wahrscheinlich die Absicht des Autors ist.
Nehmen wir einmal an, du entscheidest dich, die übliche Reihenfolge zu ignorieren und deine Links stattdessen alphabetisch zu ordnen. Das würde zu folgendem Ergebnis führen:
a
:active
{
color
:
orange
;}
a
:focus
{
color
:
green
;}
a
:hover
{
color
:
red
;}
a
:link
{
color
:
blue
;}
a
:visited
{
color
:
purple
;}
In dieser Reihenfolge würde kein Link jemals die Stile :hover
, :focus
oder :active
anzeigen, weil die Regeln :link
und :visited
nach den anderen drei kommen. Jeder Link muss entweder besucht oder nicht besucht werden, daher haben diese Stile immer Vorrang vor den anderen.
Betrachten wir eine Variante der LVFHA-Reihenfolge, die ein Autor vielleicht verwenden möchte. In dieser Reihenfolge erhalten nur nicht besuchte Links einen Hover-Stil, besuchte Links jedoch nicht. Sowohl besuchte als auch nicht besuchte Links erhalten einen aktiven Stil:
a
:link
{
color
:
blue
;}
a
:hover
{
color
:
red
;}
a
:visited
{
color
:
purple
;}
a
:focus
{
color
:
green
;}
a
:active
{
color
:
orange
;}
Solche Konflikte entstehen nur, wenn alle Staaten versuchen, die gleiche Eigenschaft zu setzen. Wenn die Stile jedes Zustands eine andere Eigenschaft ansprechen, spielt die Reihenfolge keine Rolle. Im folgenden Fall könnten die Linkstile in beliebiger Reihenfolge angegeben werden und würden trotzdem wie vorgesehen funktionieren:
a
:link
{
font-weight
:
bold
;}
a
:visited
{
font-style
:
italic
;}
a
:focus
{
color
:
green
;}
a
:hover
{
color
:
red
;}
a
:active
{
background
:
yellow
;}
Du hast vielleicht auch bemerkt, dass die Reihenfolge der Stile :link
und :visited
keine Rolle spielt. Du könntest die Stile LVFHA oder VLFHA bestellen, ohne dass dies negative Auswirkungen hätte.
Die Möglichkeit, Pseudoklassen miteinander zu verknüpfen, beseitigt all diese Sorgen. Die folgenden Pseudoklassen können in beliebiger Reihenfolge ohne Überschreibungen aufgeführt werden, da die Spezifität der letzten beiden Pseudoklassen größer ist als die der ersten beiden:
a
:link
{
color
:
blue
;}
a
:visited
{
color
:
purple
;}
a
:link:hover
{
color
:
red
;}
a
:visited:hover
{
color
:
gray
;}
Da jede Regel nur für einen bestimmten Satz von Linkzuständen gilt, widersprechen sie sich nicht. Wenn du die Reihenfolge der Regeln änderst, ändert sich das Styling des Dokuments also nicht. Die letzten beiden Regeln haben die gleiche Spezifität, aber das spielt keine Rolle. Für einen schwebenden, nicht besuchten Link gilt die Regel für schwebende, besuchte Links nicht und andersherum. Wenn wir Stile für den aktiven Zustand hinzufügen würden, würde die Reihenfolge wieder eine Rolle spielen. Stell dir das vor:
a
:link
{
color
:
blue
;}
a
:visited
{
color
:
purple
;}
a
:link:hover
{
color
:
red
;}
a
:visited:hover
{
color
:
gray
;}
a
:link:active
{
color
:
orange
;}
a
:visited:active
{
color
:
silver
;}
Wenn die aktiven Stile vor den Hover-Styles verschoben würden, würden sie ignoriert werden. Auch dies würde aufgrund von Spezifitätskonflikten geschehen. Die Konflikte könnten vermieden werden, indem man mehr Pseudoklassen zu den Ketten hinzufügt, etwa so:
a
:link:hover:active
{
color
:
orange
;}
a
:visited:hover:active
{
color
:
silver
;}
Dadurch wird die Spezifität der Selektoren erhöht - beide haben einen Spezifitätswert von 0,3,1
-, aber sie widersprechen sich nicht, weil die tatsächlichen Auswahlzustände sich gegenseitig ausschließen. Ein Link kann nicht gleichzeitig ein aktiver Link sein , wenn er besucht wird , und ein aktiver Link, wenn er nicht besucht wird: Nur eine der beiden Regeln wird zutreffen.
Arbeiten mit Nicht-CSS-Präsentationshinweisen
Ein Dokument kann Darstellungshinweise enthalten, die nicht CSS sind, z. B. das veraltete Element <font>
oder die immer noch sehr häufig verwendeten Attribute height
, width
und hidden
. Solche Darstellungshinweise werden von den Stilen des Autors oder Lesers überschrieben, nicht aber von den Stilen des User Agents. In modernen Browsern werden Präsentationshinweise von außerhalb von CSS so behandelt, als gehörten sie zum Stylesheet des User Agents.
Zusammenfassung
Der vielleicht grundlegendste Aspekt von Cascading Style Sheets ist die Kaskade selbst - der Prozess, mit dem widersprüchliche Deklarationen aussortiert und die endgültige Darstellung des Dokuments festgelegt wird. Ein wesentlicher Bestandteil dieses Prozesses ist die Besonderheit der Selektoren und der mit ihnen verbundenen Deklarationen sowie der Mechanismus der Vererbung.
Get CSS: The Definitive Guide, 5. Auflage now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.