Dies ist eines der bekanntesten Beispiele für Autoren, die falsch verstehen, wie es :first-child
funktioniert. Eingeführt in CSS2 , die :first-child
darstellt , pseudo-Klasse das erste Kind seiner Eltern . Das ist es. Es gibt ein sehr häufiges Missverständnis, dass es jedes untergeordnete Element aufgreift, das als erstes den Bedingungen entspricht, die vom Rest des zusammengesetzten Selektors angegeben werden. Aufgrund der Arbeit Selektoren Art und Weise (siehe hier für eine Erklärung), die einfach nicht wahr ist.
Selektorebene 3 führt eine :first-of-type
Pseudoklasse ein , die das erste Element unter den Geschwistern seines Elementtyps darstellt. Diese Antwort erklärt anhand von Abbildungen den Unterschied zwischen :first-child
und :first-of-type
. Wie :first-child
bei werden jedoch keine anderen Bedingungen oder Attribute berücksichtigt. In HTML wird der Elementtyp durch den Tag-Namen dargestellt. In der Frage ist dieser Typ p
.
Leider gibt es keine ähnliche :first-of-class
Pseudoklasse zum Abgleichen des ersten untergeordneten Elements einer bestimmten Klasse. Eine Problemumgehung , die Lea Verou und ich uns dafür ausgedacht haben (wenn auch völlig unabhängig), besteht darin, zuerst Ihre gewünschten Stile auf alle Ihre Elemente mit dieser Klasse anzuwenden :
/*
* Select all .red children of .home, including the first one,
* and give them a border.
*/
.home > .red {
border: 1px solid red;
}
... dann "rückgängig machen" Sie die Stile für Elemente mit der Klasse, die nach der ersten kommen , unter Verwendung des allgemeinen Geschwisterkombinators~
in einer übergeordneten Regel:
/*
* Select all but the first .red child of .home,
* and remove the border from the previous rule.
*/
.home > .red ~ .red {
border: none;
}
Jetzt hat nur das erste Element mit class="red"
einen Rand.
Hier ist eine Illustration, wie die Regeln angewendet werden:
<div class="home">
<span>blah</span> <!-- [1] -->
<p class="red">first</p> <!-- [2] -->
<p class="red">second</p> <!-- [3] -->
<p class="red">third</p> <!-- [3] -->
<p class="red">fourth</p> <!-- [3] -->
</div>
Es werden keine Regeln angewendet. Es wird kein Rand gerendert.
Dieses Element hat keine Klasse red
, daher wird es übersprungen.
Es wird nur die erste Regel angewendet. Ein roter Rand wird gerendert.
Dieses Element hat die Klasse red
, aber es werden keine Elemente mit der Klasse red
im übergeordneten Element vorangestellt . Somit wird nicht die zweite Regel angewendet, sondern nur die erste, und das Element behält seinen Rand.
Beide Regeln werden angewendet; Es wird kein Rand gerendert.
Dieses Element hat die Klasse red
. Es wird auch mindestens ein weiteres Element mit der Klasse vorangestellt red
. Somit werden beide Regeln angewendet, und die zweite border
Deklaration überschreibt die erste, wodurch sie sozusagen "rückgängig gemacht" wird.
Als Bonus wird der allgemeine Geschwisterkombinator, obwohl er in Selectors 3 eingeführt wurde, von IE7 und neueren Versionen im Gegensatz zu :first-of-type
und ziemlich gut unterstützt:nth-of-type()
die nur weiter mit dem IE9 unterstützt werden. Wenn Sie gute Browserunterstützung benötigen, haben Sie Glück.
Die Tatsache, dass der Geschwisterkombinator die einzige wichtige Komponente in dieser Technik ist und eine so erstaunliche Browserunterstützung bietet, macht diese Technik sehr vielseitig - Sie können sie neben den Klassenselektoren auch zum Filtern von Elementen durch andere Dinge anpassen:
Sie können dies verwenden, um :first-of-type
in IE7 und IE8 zu umgehen, indem Sie einfach einen Typ-Selektor anstelle eines Klassen-Selektors angeben (mehr zu seiner falschen Verwendung hier in einem späteren Abschnitt):
article > p {
/* Apply styles to article > p:first-of-type, which may or may not be :first-child */
}
article > p ~ p {
/* Undo the above styles for every subsequent article > p */
}
Sie können anstelle von Klassen nach Attributselektoren oder anderen einfachen Selektoren filtern .
Sie können diese übergeordnete Technik auch mit Pseudoelementen kombinieren , obwohl Pseudoelemente technisch gesehen keine einfachen Selektoren sind.
Beachten Sie, dass Sie im Voraus wissen müssen, welche Standardstile für Ihre anderen Geschwisterelemente verwendet werden, damit Sie die erste Regel überschreiben können. Da dies das Überschreiben von Regeln in CSS beinhaltet, können Sie mit einem einzelnen Selektor zur Verwendung mit der Selectors-API oder Selenium nicht dasselbe erreichen den CSS-Locators von .
Es ist erwähnenswert, dass Selectors 4 eine Erweiterung der :nth-child()
Notation einführt (ursprünglich eine völlig neue Pseudoklasse namens :nth-match()
), mit der Sie so etwas wie :nth-child(1 of .red)
anstelle einer Hypothese verwenden können .red:first-of-class
. Da es sich um einen relativ neuen Vorschlag handelt, gibt es noch nicht genügend interoperable Implementierungen, um ihn in Produktionsstätten verwenden zu können. Hoffentlich ändert sich das bald. In der Zwischenzeit sollte die von mir vorgeschlagene Problemumgehung in den meisten Fällen funktionieren.
Beachten Sie, dass diese Antwort davon ausgeht, dass die Frage nach jedem ersten untergeordneten Element sucht, das eine bestimmte Klasse hat. Es gibt weder eine Pseudoklasse noch eine generische CSS-Lösung für die n-te Übereinstimmung eines komplexen Selektors im gesamten Dokument - ob eine Lösung vorhanden ist, hängt stark von der Dokumentstruktur ab. jQuery bietet :eq()
, :first
, :last
und zu diesem Zweck, aber beachten Sie wieder , dass sie funktionieren ganz anders :nth-child()
et al . Mit der Selectors-API können Sie entweder document.querySelector()
die allererste Übereinstimmung erzielen:
var first = document.querySelector('.home > .red');
Oder verwenden Sie document.querySelectorAll()
einen Indexer, um eine bestimmte Übereinstimmung auszuwählen:
var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc
Obwohl die .red:nth-of-type(1)
Lösung in der ursprünglich akzeptierten Antwort von Philip Daubmeier funktioniert (die ursprünglich von Martyn geschrieben, aber seitdem gelöscht wurde), verhält sie sich nicht so, wie Sie es erwarten würden.
Wenn Sie beispielsweise nur das p
in Ihrem ursprünglichen Markup auswählen möchten:
<p class="red"></p>
<div class="red"></div>
... dann zu verwenden , kann man nicht .red:first-of-type
(entspricht .red:nth-of-type(1)
), da jedes Element der ersten (und einzigen) einer ihrer Art (ist p
und div
jeweils), so dass beide werden durch den Selektor angepasst werden.
Wenn das erste Element einer bestimmten Klasse auch das erste seiner Art ist , funktioniert die Pseudoklasse, dies geschieht jedoch nur durch Zufall . Dieses Verhalten wird in Philipps Antwort demonstriert. Sobald Sie ein Element des gleichen Typs vor diesem Element einfügen, schlägt die Auswahl fehl. Nehmen Sie das aktualisierte Markup:
<div class="home">
<span>blah</span>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
Das Anwenden einer Regel mit .red:first-of-type
funktioniert, aber sobald Sie eine andere p
ohne die Klasse hinzufügen :
<div class="home">
<span>blah</span>
<p>dummy</p>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
... der Selektor schlägt sofort fehl, da das erste .red
Element jetzt das zweite p
Element ist.