Warum funktioniert .class: last-of-type nicht wie erwartet?

72

Warum funktioniert das nicht? http://jsfiddle.net/84C5W/1/

p{
    display: none;
}
p.visible:last-of-type {
    display: block;
}
<div>
  <p class="visible">This should be hidden</p>
  <p class="visible">This should be displayed</p>
  <p class="">This should be hidden</p>
</div>

Tatsächlich ist keines meiner <p>Elemente sichtbar. Wenn ich den Verweis auf .visiblein meinem Selektor entferne , wird der letzte <p>im div angezeigt, aber das ist nicht das, was ich will.

Natürlich konnte ich immer nur eine behalten .visible, aber dies ist für eine Präsentation von enthüllen.js und ich habe keine Kontrolle über das JavaScript.

Wie kann ich das letzte Element innerhalb des div WITH der Klasse auswählen .visible? Ich möchte dafür KEIN JavaScript verwenden.

Øystein Amundsen
quelle

Antworten:

112

Ihr Problem ist, dass Sie lesen :last-of-typeund denken, dass es als :last-of-classSelektor funktioniert , wenn es stattdessen speziell nur Elemente bedeutet . Leider gibt es keinen Selektor für die letzte Instanz einer Klasse.

Aus dem W3C :

Die :last-of-typePseudoklasse repräsentiert ein Element, das das letzte Geschwister seines Typs ist.

Sie haben p.visible:last-of-typeals Selektor Folgendes ausgewählt:

  1. untersucht jede Liste von Elementen (z. B. 1 oder mehrere Elemente; ein Kind ohne Geschwister kann noch darauf :last-of-typeangewendet haben) in jedem enthaltenden Element in Ihrem HTML
  2. findet das letzte Element in dieser Liste
  3. prüft, ob es sich um ein <p>Element handelt
  4. Überprüft, ob die Klasse .visibledarauf ist.

Kurz gesagt, Ihr Selektor wendet seine Stile nur auf a an <p> , auf dem sich auch die Klasse befindet .visible. In Ihrem Markup haben nur die ersten beiden <p>Elemente diese Klasse. der dritte nicht.

Hier ist eine Demo verschiedener Stile zur Veranschaulichung:

p:last-of-type {
  /* this will be applied in the third paragraph because the pseudo-selector checks for nodes only */
  color: green;
}
p.visible:last-of-type {
  /* this does not get applied, because you are using the pseudo-selector with a specific class in addition to the node type. */
  color: red;
}
<p class="visible">First paragraph.</p>
<p class="visible">Second paragraph.</p>
<p>Third paragraph.</p>

Gemäß Ihrem Endziel,

Wie kann ich das letzte Element innerhalb des div WITH der Klasse .visible auswählen? Ich möchte dafür KEIN JavaScript verwenden.

Der einfachste und performanteste Weg besteht darin, die Art und Weise umzukehren, in der Sie versuchen, die Stile anzuwenden. Anstatt zu versuchen, zwei von drei Divs auszublenden, hat einer der auszublendenden Divs eine Klasse und der andere auszublendende Div keine Klasse, und der Div, den Sie anzeigen möchten, hat dieselbe Klasse wie der eine Div, den Sie ausblenden möchten die auch eine Klasse hat (siehe? das ist ziemlich verwirrend), mache folgendes:

  • Fügen Sie die Klasse nur dem Element (oder der Gruppe von Elementen) hinzu, das kleiner ist.
  • Legen Sie den Standardstil für das Element so fest, wie er von der Klasse nicht erreicht werden soll.
  • Stellen Sie den Stil für die Klasse so ein, wie Sie es erreichen möchten.

p {
    display: none;
}
.visible {
    display: block;
}
<div>
    <p>This should be hidden</p>
    <p class="visible">This should be displayed</p>
    <p>This should be hidden</p>
</div>

Wie Sie dieser Demo entnehmen können, sind HTML und CSS nicht nur einfacher, sondern es besteht auch der Vorteil, dass nur ein Klassen-Selektor anstelle eines *-of-typePseudo-Selektors verwendet wird, wodurch die Seite schneller geladen wird (mehr dazu weiter unten). .

Warum gibt es keinen von oder übergeordneten Selektor ? Dies könnte möglicherweise die Geschwindigkeit vieler Webseiten beeinträchtigen, indem nur ein Klassenname dynamisch auf der Seite geändert wird.

Dave Hyatt nannte bei der Arbeit an der WebKit-Implementierung im Jahr 2008 einige Gründe, warum diese Implementierungen vermieden werden :

Mit übergeordneten Selektoren wird es extrem einfach, versehentlich ein dokumentweites Grovel zu verursachen. Menschen können und werden diesen Selektor missbrauchen. Es zu unterstützen bedeutet, den Menschen eine Menge Seil zu geben, mit dem sie sich aufhängen können.

Die traurige Wahrheit über CSS3-Selektoren ist, dass sie wirklich überhaupt nicht verwendet werden sollten, wenn Sie sich für die Seitenleistung interessieren. Wenn Sie Ihr Markup mit Klassen und IDs dekorieren und nur mit diesen übereinstimmen und dabei alle Verwendungen von Geschwister-, Nachkommen- und Kinder-Selektoren vermeiden, wird die Leistung einer Seite in allen Browsern erheblich verbessert.

Justus Romijn
quelle
7

Zielen Sie auf das vorletzte Tag.

.visible:nth-last-of-type(2) {}
Thisismint
quelle
3
Ich weiß, aber das will ich nicht. Der Hinweis ist, dass die Elemente dynamisch sein können und ich nicht an eine bestimmte Elementposition in meinem CSS binden möchte.
Øystein Amundsen
1
Okay, aber meine Antwort ist für andere Menschen, die ein ähnliches Dilemma erleben. keine nachfolgenden Knoten / Tags hinzufügen.
Thisismint
5

Zum späteren Nachschlagen wird dies in CSS Level 4 behandelt: https://www.w3.org/TR/selectors4/#the-nth-last-match-pseudo

Browserunterstützung ist zum Zeitpunkt des Schreibens nicht vorhanden: http://css4-selectors.com/selector/css4/structural-pseudo-class/

Wenn dies fertig ist, sollte dies die Lösung sein:

p {
  display : none;
}
p.visible:nth-last-match(0) {
  display : block;
}
<div>
  <p class="visible">This should be hidden</p>
  <p class="visible">This should be displayed</p>
  <p class="">This should be hidden</p>
</div>

Øystein Amundsen
quelle
Es gibt noch keine Browser-Unterstützung dafür: /
Anant Gupta
1
Ich weiß, es sieht so aus, als hätten sie dies aus der vorgeschlagenen Spezifikation gestrichen.
Øystein Amundsen
0

Auf diese Weise bin ich um das Problem außerhalb der Klasse herumgekommen - es ist leider eine Javascript-Lösung:

function lastOfType(className){
            var allElemsOfType = document.getElementsByClassName(className);
            if (!allElemsOfType || !allElemsOfType.length) return null;
            else return allElemsOfType[allElemsOfType.length - 1];
    }

lastOfType('visible').style.display = 'block'
.visible {
  display: none;
}

p {
  display: none;
}
<p class='visible'>1</p>
<p class='visible'>2</p>
<p>3</p>

Judy Engelsman
quelle