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+b
gdziekolwiek a != 1
i 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ą tr
elementy, lub elementu listy, którego jedynymi dziećmi są li
elementy, 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 tr
element, który spełnia wszystkie poniższe niezależne warunki:
- jest nieparzystym dzieckiem swojego rodzica;
- ma klasę „row”; i
- jest potomkiem
table
elementu, 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 tr
elementami 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 tr
i :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ż tr
elementy 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.