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

117

Есть ли способ выбрать каждого 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элементы независимо от того, относятся ли они к классу «строка», поэтому я получаю один четный элемент «строка» вместо двух, которые я ищу. То же самое происходит с :nth-of-type().

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

Атанамир
источник

Ответы:

144

Это очень частая проблема, возникающая из-за непонимания того, как :nth-child()и :nth-of-type()работают. К сожалению, в настоящее время нет решения на основе селектора, потому что Selectors не предоставляет способ сопоставления 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().

BoltClock
источник
3
«(вы заметите, что я использую здесь неупорядоченный список, просто чтобы довести дело до конца)» Я бы хотел, чтобы больше людей осознанно использовали упорядоченные и неупорядоченные маркеры. Спасибо за ваш ответ.
The Red Pea
1
@The Red Pea: Одна из моих самых больших неприятностей в HTML: «В порядке от самого высокого / самого низкого до самого низкого / самого высокого:», за которым следует неупорядоченный список. Я имею в виду давай, серьезно?
BoltClock
6

На самом деле, нет..

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

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

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

Габриэле Петриоли
источник
0

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

но если вы используете css типа nth, это может быть

.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 к 1-му, 2-му, 3-му, 4-му, 5-му элементу <p>.

Гаурав Аггарвал
источник
Насколько это полезно для <tr>тегов?
Alexis Wilke
0

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

the8472
источник
0

Вот твой ответ

<!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
источник
0

Все вопросы, связанные с использованием nth-child и пропуском скрытых тегов, похоже, перенаправляются как дубликаты этого, поэтому я оставлю это здесь. Я наткнулся на этот блог https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/ который использует умный подход css, чтобы nth-child игнорировал скрытые элементы, следующим образом:

Следующий CSS добавляет право поля к каждому второму видимому элементу независимо от того, какой элемент имеет класс 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;
}

Надеюсь, это поможет кому-то, кто идет по обманчивой тропе в вопросах игнорирования скрытых элементов!

IrishDubGuy
источник
1
Я бы хотел проголосовать за это, но для этого нужна рабочая демонстрация.
Moob
Я помню, что на самом деле это было не так надежно, как казалось изначально - теперь я бы выбрал самый популярный комментарий, это невозможно.
IrishDubGuy
0

ЕСЛИ у вас есть один и тот же родительский класс для всех селекторов, тогда вы используете этот класс, document.querySelector("main .box-value:nth-child(3) select.priorityOption"); потому что в этом случае document.querySelector("main .box-value select.priorityOption:nth-child(3)");не работает. Спасибо

<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>
Джатин Аггарвал
источник