Czy mogę łączyć: nth-child () lub: nth-of-type () z dowolnym selektorem?

117

Czy istnieje sposób na wybranie każdego n-tego dziecka, które pasuje (lub nie pasuje) do dowolnego selektora ? Na przykład chcę zaznaczyć każdy nieparzysty wiersz tabeli, ale w podzbiorze wierszy:

table.myClass tr.row:nth-child(odd) {
  ...
}
<table class="myClass">
  <tr>
    <td>Row
  <tr class="row"> <!-- I want this -->
    <td>Row
  <tr class="row">
    <td>Row
  <tr class="row"> <!-- And this -->
    <td>Row
</table>

Ale :nth-child()po prostu wydaje się liczyć wszystkie trelementy, niezależnie od tego, czy należą do klasy „row”, czy nie, więc otrzymuję jeden równy element „row” zamiast dwóch, których szukam. To samo dzieje się z :nth-of-type().

Czy ktoś może wyjaśnić, dlaczego?

atanamir
źródło

Odpowiedzi:

144

Jest to bardzo częsty problem, który pojawia się w wyniku niezrozumienia sposobu :nth-child()i :nth-of-type()pracy. Niestety, obecnie nie ma jeszcze rozwiązania opartego na selektorach, ponieważ selektory nie zapewniają sposobu dopasowania n-tego elementu podrzędnego, który pasuje do dowolnego selektora na podstawie wzorca takiego jak nieparzyste, parzyste lub an+bgdziekolwiek a != 1i b != 0. To wykracza poza selektory klas, do selektorów atrybutów, negacji i bardziej złożonych kombinacji prostych selektorów.

:nth-child()Pseudo-klasa liczy pierwiastki spośród wszystkich ich rodzeństwa w ramach tego samego rodzica. Nie uwzględnia tylko rodzeństwa, które pasuje do reszty selektora. Podobnie, :nth-of-type()pseudoklasa liczy rodzeństwo o tym samym typie elementu, który odwołuje się do nazwy znacznika w HTML, a nie do reszty selektora.

Oznacza to również, że jeśli wszystkie dzieci tego samego rodzica są tego samego typu elementu, na przykład w przypadku treści tabeli, której jedynymi dziećmi są trelementy, lub elementu listy, którego jedynymi dziećmi są lielementy, to :nth-child()i :nth-of-type()będą zachowywać się identycznie, tj. dla każdej wartości an+b, :nth-child(an+b)i :nth-of-type(an+b)będzie pasował do tego samego zestawu elementów.

W rzeczywistości wszystkie proste selektory w danym selektorze złożonym, w tym pseudoklasy, takie jak :nth-child()i :not(), działają niezależnie od siebie, zamiast patrzeć na podzbiór elementów, które są dopasowane przez resztę selektora.

Oznacza to również, że nie ma pojęcia porządku wśród selektorów prostych w każdym selektorze złożonym 1 , co oznacza, że ​​na przykład następujące dwa selektory są równoważne:

table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row

W tłumaczeniu na angielski oba mają na myśli:

Wybierz dowolny trelement, który spełnia wszystkie poniższe niezależne warunki:

  • jest nieparzystym dzieckiem swojego rodzica;
  • ma klasę „row”; i
  • jest potomkiem tableelementu, który ma klasę „myClass”.

(zauważysz, że używam tutaj nieuporządkowanej listy, tylko po to, aby zwrócić uwagę do domu)

Ponieważ obecnie nie ma czystego rozwiązania CSS, będziesz musiał użyć skryptu do filtrowania elementów i odpowiedniego stosowania stylów lub dodatkowych nazw klas. Na przykład, poniżej przedstawiono typowe obejście problemu przy użyciu jQuery (zakładając, że istnieje tylko jedna grupa wierszy wypełniona trelementami w tabeli):

$('table.myClass').each(function() {
  // Note that, confusingly, jQuery's filter pseudos are 0-indexed
  // while CSS :nth-child() is 1-indexed
  $('tr.row:even').addClass('odd');
});

Z odpowiednim CSS:

table.myClass tr.row.odd {
  ...
}

Jeśli używasz zautomatyzowanych narzędzi testujących, takich jak Selenium, lub przetwarzasz HTML za pomocą narzędzi takich jak lxml, wiele z tych narzędzi zezwala na XPath jako alternatywę:

//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]

Inne rozwiązania wykorzystujące różne technologie pozostawiono czytelnikowi jako ćwiczenie; to tylko krótki, wymyślony przykład dla ilustracji.


Warto, jest propozycja rozszerzenia :nth-child()notacji, która ma być dodana do poziomu selektorów 4 w celu wybrania co n-tego dziecka pasującego do danego selektora. 2

Selektor, za pomocą którego mają być filtrowane dopasowania, jest podawany jako argument :nth-child(), również z powodu tego, jak selektory działają niezależnie od siebie w sekwencji, zgodnie z istniejącą składnią selektora. W twoim przypadku wyglądałoby to tak:

table.myClass tr:nth-child(odd of .row)

(Wnikliwy czytelnik od razu zauważy, że powinno to być :nth-child(odd of tr.row)zamiast tego, ponieważ proste selektory tri :nth-child()działają niezależnie od siebie. Jest to jeden z problemów związanych z funkcjonalnymi pseudoklasami, które akceptują selektory, puszką robaków. raczej nie otwierać w środku tej odpowiedzi. Zamiast tego wychodzę z założenia, że ​​większość witryn nie będzie miała żadnych innych elementów niż trelementy jako rodzeństwo w treści tabeli, co sprawiłoby, że każda opcja byłaby funkcjonalnie równoważna.)

Oczywiście, będąc zupełnie nową propozycją w zupełnie nowej specyfikacji, prawdopodobnie nie doczeka się wdrożenia aż do kilku lat później. W międzyczasie będziesz musiał trzymać się skryptu, jak powyżej.


1 Jeśli określisz typ lub selektor uniwersalny, musi on być pierwszy. Nie zmienia to jednak zasadniczego sposobu działania selektorów; to nic innego jak dziwactwo syntaktyczne.

2 Zostało to pierwotnie zaproponowane :nth-match(), jednak ponieważ nadal liczy element w odniesieniu tylko do swojego rodzeństwa, a nie do każdego innego elementu, który pasuje do danego selektora, od 2014 r. Został zmieniony jako rozszerzenie istniejącego :nth-child()zamiast tego.

BoltClock
źródło
3
„(Zauważysz, że używam tutaj nieuporządkowanej listy, tylko po to, żeby wyjaśnić sprawę)„ Chciałbym, aby więcej ludzi było tak świadomych, jeśli chodzi o użycie pocisków zamówionych i nieuporządkowanych. Dziękuję za Twoją odpowiedź.
The Red Pea
1
@ The Red Pea: Jedna z moich największych irytacji HTML: „W kolejności od najwyższego / najniższego do najniższego / najwyższego:”, po którym następuje nieuporządkowana lista. No dalej, poważnie?
BoltClock
6

Nie całkiem..

cytat z dokumentów

:nth-childPseudoklasa pasuje do elementu, który posiada + b-1 rodzeństwa przed nią drzewa dokumentu , dla danego dodatnim lub zerowym wartości dla n oraz ma element nadrzędny.

Jest selektorem własnym i nie łączy się z klasami. W twojej regule musi po prostu spełniać oba selektory w tym samym czasie, więc pokaże :nth-child(even)wiersze tabeli, jeśli akurat mają .rowklasę.

Gabriele Petrioli
źródło
0

nth-of-typedziała zgodnie z indeksem tego samego typu elementu, ale nth-childdziała tylko zgodnie z indeksem, niezależnie od typu elementów rodzeństwa.

Na przykład

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>

Załóżmy, że w powyższym html chcemy ukryć wszystkie elementy mające klasę reszt.

W tym przypadku nth-childi nth-of-typebędzie działać dokładnie tak samo, jak wszystkie elementy są tego samego typu, czyli <div>tak powinno być w css

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10){
    display:none;
}

LUB

.rest:nth-of-type(6), .rest:nth-of-type(7), .rest:nth-of-type(8), .rest:nth-of-type(9), .rest:nth-of-type(10){
    display:none;
}

Teraz musisz się zastanawiać, jaka jest różnica między, nth-childa nth-of-typewięc to jest różnica

Załóżmy, że kod HTML to

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>

W powyższym html typ .restelementu różni się od innych .restto akapity a inne to div więc w tym przypadku jeśli używasz nth-childmusisz pisać tak

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10){
    display:none;
}

ale jeśli używasz css n-tego typu, może to być to

.rest:nth-of-type(1), .rest:nth-of-type(2), .rest:nth-of-type(3), .rest:nth-of-type(4), .rest:nth-of-type(5){
    display:none;
}

Ponieważ typ .restelementu jest <p>taki, tutaj nth-of-typejest wykrywanie typu, .resta następnie zastosował css na 1., 2., 3., 4., 5. elemencie <p>.

Gaurav Aggarwal
źródło
Jak przydatne jest to w przypadku <tr>tagów?
Alexis Wilke,
0

Możesz to zrobić za pomocą xpath. coś takiego //tr[contains(@class, 'row') and position() mod 2 = 0]może zadziałać. Istnieją inne pytania SO rozszerzające szczegóły, jak dokładniej dopasować klasy.

the8472
źródło
0

Oto twoja odpowiedź

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>TEST</title>

  <style>

    .block {
      background: #fc0;
      margin-bottom: 10px;
      padding: 10px;
    }
    /* .large > .large-item:nth-of-type(n+5) {
      background: #f00;
    } */

    .large-item ~ .large-item ~ .large-item ~ .large-item ~ .large-item {
      background: #f00;
    }

  </style>
</head>
<body>

<h1>Should be the 6th Hello Block that start red</h1>
<div class="small large">
  <div class="block small-item">Hello block 1</div>
  <div class="block small-item large-item">Hello block 2</div>
  <div class="block small-item large-item">Hello block 3</div>
  <div class="block small-item large-item">Hello block 4</div>
  <div class="block small-item large-item">Hello block 5</div>
  <div class="block small-item large-item">Hello block 6</div>
  <div class="block small-item large-item">Hello block 7</div>
  <div class="block small-item large-item">Hello block 8</div>
</div>

</body>
</html>
Pocketninja
źródło
0

Wszystkie pytania dotyczące używania nth-child i pomijania ukrytych tagów wydają się być przekierowaniami tego typu, więc zostawię to tutaj. Natknąłem się na tego bloga https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/, który wykorzystuje sprytne podejście CSS, aby nth-child ignorowało ukryte elementy, następująco:

Poniższy kod CSS dodaje margines do każdego drugiego widocznego elementu, niezależnie od tego, który element ma klasę cpw.

.cpw {
    display:none;
}

.video_prewrap {
    margin-right:20px;
}

.video_prewrap:nth-child(2n) {
    margin-right:0;
}

.cpw ~ .video_prewrap:nth-child(2n) {
    margin-right:20px;
}

.cpw ~ .video_prewrap:nth-child(2n-1) {
    margin-right:0;
}

Mam nadzieję, że pomoże to komuś, kto podąża fałszywym tropem, aby ignorować pytania dotyczące ukrytych elementów!

IrishDubGuy
źródło
1
Chciałbym to zagłosować, ale potrzebna jest działająca wersja demonstracyjna.
Moob
Przypominam sobie, że w rzeczywistości nie było to tak solidne, jak się początkowo wydawało - skorzystałbym teraz z komentarza z największą liczbą głosów, to niemożliwe.
IrishDubGuy
0

JEŚLI masz tę samą klasę nadrzędną dla wszystkich selektorów, to używasz tej klasy, document.querySelector("main .box-value:nth-child(3) select.priorityOption"); ponieważ w tym przypadku document.querySelector("main .box-value select.priorityOption:nth-child(3)");nie działa. Dziękuję Ci

<div class="card table">
    <div class="box">
        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>
    </div>
</div>
Jatin Aggarwal
źródło