Ответ 1
Это очень распространенная проблема, возникающая из-за непонимания работы :nth-child()
и :nth-of-type()
. К сожалению, в настоящее время нет решения на основе селектора, поскольку Селекторы не обеспечивают способ соответствия n-му ребенку, который соответствует произвольному селектору, основанному на шаблоне, таком как нечетный, четный или любой an+b
, где a != 1
и b != 0
. Это распространяется не только на селекторов классов, а на атрибуты селекторов, отрицаний и более сложные комбинации простых селекторов.
:nth-child()
pseudo-class подсчитывает элементы среди всех своих братьев и сестер под одним и тем же родителем. Он не учитывает только братьев и сестер, которые соответствуют остальной части селектора. Аналогично, :nth-of-type()
pseudo-class подсчитывает, что сиблины используют один и тот же тип элемента, который ссылается на имя тега в 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, вам придется использовать script для фильтрации элементов и соответственно применять стили или дополнительные имена классов. Например, следующее обходное решение с использованием jQuery (предполагая, что в таблице есть только одна группа строк, заполненная элементами tr
):
$('table.myClass').each(function() {
// Note that, confusingly, jQuery 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
, таких как братья и сестры одного другой в теле таблицы, что сделает любой вариант функционально эквивалентным.)
Конечно, будучи совершенно новым предложением в совершенно новой спецификации, это, вероятно, не увидит реализацию до нескольких лет в будущем. В то же время вам придется придерживаться script, как указано выше.
1 Если вы укажете тип или универсальный селектор, он должен быть первым. Однако это не меняет того, как работают селекторы. это не более чем синтаксическая причуда.
2 Первоначально это было предложено как :nth-match()
, однако, поскольку оно по-прежнему считает элемент относительным только для его братьев и сестер, а не для каждого другого элемента, который соответствует данному селектору, он с тех пор, как с 2014 года был перераспределен как расширение к существующий :nth-child()
.