Это очень распространенная проблема, которая возникает из-за неправильного понимания того, как :nth-child()
и :nth-of-type()
работают. К сожалению, в настоящее время пока нет решения на основе селектора, поскольку селекторы не обеспечивают способ сопоставления n-го дочернего элемента, который соответствует произвольному селектору, на основе шаблона, такого как нечетный, четный или любой an+b
, где a != 1
и b != 0
. Это распространяется не только на селекторы классов, но и на атрибуты селекторов, отрицания и более сложные комбинации простых селекторов.
Псевдокласс :nth-child()
считает элементы среди всех их братьев и сестер под одним и тем же родителем. Он не учитывает только тех братьев и сестер, которые соответствуют остальной части селектора. Аналогично, псевдокласс :nth-of-type()
считает братьев и сестер, имеющих один и тот же тип элемента, который ссылается на имя тега в HTML, а не на остальную часть селектора.
Это также означает, что если все дочерние элементы одного и того же родителя имеют одинаковый тип элемента, например, в случае тела таблицы, единственными дочерними элементами которого являются элементы tr
, или элемента списка, единственными дочерними элементами которого являются li
элементы, тогда :nth-child()
и :nth-of-type()
будут вести себя одинаково, то есть для каждого значения an+b
, :nth-child(an+b)
и :nth-of-type(an+b)
будут совпадать с одним и тем же набором элементов.
Фактически, все простые селекторы в данном составном селекторе, включая псевдоклассы, такие как :nth-child()
и :not()
, работают независимо друг от друга, а не смотрят на подмножество элементов, которые соответствуют остальной части селектора.
Это также означает, что не существует понятия порядка среди простых селекторов в каждом отдельном составном селекторе 1 , что означает, например, что следующие два селектора эквивалентны:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
В переводе на английский они оба означают:
Выберите любой элемент tr
, который соответствует всем следующим независимым условиям:
- это нечетный потомок своего родителя;
- имеет класс «ряд»; и
- это потомок элемента
table
, который имеет класс "myClass".
(вы заметите, что я здесь использую неупорядоченный список, просто чтобы показать точку)
Поскольку в настоящее время нет чистого решения CSS, вам придется использовать скрипт для фильтрации элементов и соответственно применять стили или дополнительные имена классов. Например, ниже приведен общий способ использования jQuery (при условии, что в таблице имеется только одна группа строк, заполненная элементами tr
):
$('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');
});
С соответствующим CSS:
table.myClass tr.row.odd {
...
}
Если вы используете инструменты автоматического тестирования, такие как Selenium, или обрабатываете HTML с помощью таких инструментов, как lxml, многие из этих инструментов позволяют использовать XPath в качестве альтернативы:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
Другие решения, использующие различные технологии, оставлены читателю в качестве упражнения; это только краткий, надуманный пример для иллюстрации.
Для чего бы то ни было, существует предложение о расширении для :nth-child()
нотации , которое будет добавлено к уровню селекторов 4 для конкретной цели выбора каждого n-го дочернего элемента, соответствующего данному селектору. 2
Селектор, с помощью которого фильтруются совпадения, предоставляется в качестве аргумента для :nth-child()
, опять же, из-за того, что селекторы работают независимо друг от друга в последовательности, что диктуется существующим синтаксисом селектора. Так что в вашем случае это будет выглядеть так:
table.myClass tr:nth-child(odd of .row)
(Проницательный читатель сразу заметит, что вместо этого должно быть :nth-child(odd of tr.row)
, поскольку простые селекторы tr
и :nth-child()
также работают независимо друг от друга. Это одна из проблем с функциональной псевдо- классы, которые принимают селекторы, банку с червями, которую я бы предпочел не открывать в середине этого ответа. Вместо этого я собираюсь исходить из предположения, что большинство сайтов не будет иметь никаких других элементов, кроме tr
элементов, как братьев и сестер одного другой в теле таблицы, что сделает любой параметр функционально эквивалентным.)
Конечно, будучи совершенно новым предложением в совершенно новой спецификации, это, вероятно, не будет реализовано в течение нескольких лет. Тем временем вам придется придерживаться сценария, как описано выше.
1 Если указать тип или универсальный селектор, он должен стоять первым. Однако это не меняет принцип работы селекторов; это не что иное, как синтаксическая причуда.
2 Первоначально он был предложен как :nth-match()
, однако, поскольку он по-прежнему считает элемент относительно только его братьев и сестер, а не каждого другого элемента, который соответствует данному селектору, по состоянию на 2014 год вместо него был переназначен как расширение к существующему :nth-child()
.