Могу ли я объединить: nth-child() или: nth-of-type() с произвольным селектором?

Есть ли способ выбрать каждый n-й дочерний элемент, который соответствует (или не соответствует) произвольному селектору? Например, я хочу выбрать каждую строку нечетной таблицы, но внутри подмножества строк:

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>

Но :nth-child() просто, кажется, подсчитывает все элементы tr независимо от того, являются ли они классом "row", поэтому я заканчиваю одним даже "строковым" элементом, а не двумя, м ищет. То же самое происходит с :nth-of-type().

Может кто-нибудь объяснить, почему?

Ответ 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().

Ответ 2

Не совсем..

цитата из документов

Псевдокласс класса :nth-child соответствует элемент, который имеет + b-1 братья и сестры перед ним в дереве документов, для заданное положительное или нулевое значение для n, и имеет родительский элемент.

Это собственный селектор и не сочетается с классами. В вашем правиле нужно просто выполнить оба селектора одновременно, поэтому он будет показывать строки таблицы :nth-child(even), если они также имеют класс .row.

Ответ 3

nth-of-type работает в соответствии с индексом того же типа элемента, но nth-child работает только в соответствии с индексом независимо от того, какой тип элементов брака находится.

Например

<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>

Предположим, что в выше html мы хотим скрыть все элементы, имеющие класс отдыха.

В этом случае nth-child и nth-of-type будут работать точно так же, как и все элементы того же типа, что и <div>, поэтому css должен быть

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

ИЛИ

.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;
}

Теперь вам должно быть интересно узнать, в чем разница между nth-child и nth-of-type, так что это разница

Предположим, что html

<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>

В вышеприведенном html тип элемента .rest отличается от других .rest - это абзацы, а другие - div, поэтому в этом случае, если вы используете nth-child, вам нужно написать вот так

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

, но если вы используете nth-of-type, это может быть

.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;
}

Поскольку тип элемента .rest равен <p>, поэтому здесь nth-of-type обнаруживает тип .rest, а затем он применяет css для первого, второго, третьего, четвертого, пятого элементов <p>.

Ответ 4

Вы можете сделать это с помощью xpath. что-то вроде //tr[contains(@class, 'row') and position() mod 2 = 0] может работать. Существуют и другие вопросы о том, как более точно сопоставлять классы.