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

#css #css-selectors

#css #css-селекторы

Вопрос:

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

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

Комментарии:

1. По состоянию на октябрь 2021 года указан nth-child(n из S) (где S — селектор), но, насколько я могу установить, в настоящее время реализован только в Safari, см., Например developer.mozilla.org/en-US/docs/Web/CSS/:nth-child

Ответ №1:

Это очень распространенная проблема, которая возникает из-за непонимания того, как :nth-child(An B) и :nth-of-type() как работать.

В селекторах уровня 3 :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 элемент, который соответствует всем следующим независимым условиям:

  • это дочерний элемент с нечетным номером своего родителя;
  • он имеет класс «row»; и
  • это потомок table элемента, который имеет класс «MyClass».

(вы заметите, что я использую здесь неупорядоченный список, просто чтобы довести дело до конца)

Уровень селекторов 4 направлен на устранение этого ограничения, позволяя :nth-child(An B of S) 2 принимать произвольный аргумент S селектора, опять же из-за того, как селекторы работают независимо друг от друга в составном селекторе, как продиктовано существующим синтаксисом селектора. Так что в вашем случае это будет выглядеть примерно так:

 table.myClass tr:nth-child(odd of .row)
 

Конечно, будучи совершенно новым предложением в совершенно новой спецификации, это, вероятно, не увидит реализации до нескольких лет в будущем.

Тем временем вам придется использовать скрипт для фильтрации элементов и применения стилей или дополнительных имен классов соответственно. Например, ниже приведен общий обходной путь с использованием 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 с помощью таких инструментов, как BeautifulSoup, многие из этих инструментов допускают XPath в качестве альтернативы:

 //table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
 

Другие решения, использующие разные технологии, оставлены в качестве упражнения для читателя; это всего лишь краткий, надуманный пример для иллюстрации.


1 Если вы указываете тип или универсальный селектор, он должен быть первым. Однако это принципиально не меняет работу селекторов; это не более чем синтаксическая причуда.

2 Первоначально это было предложено как :nth-match() , однако, поскольку он по-прежнему учитывает элемент относительно только его братьев и сестер, а не любого другого элемента, соответствующего данному селектору, с 2014 года он был перепрофилирован как расширение существующего :nth-child() . вместо этого.

Комментарии:

1. «(вы заметите, что я использую здесь неупорядоченный список, просто чтобы довести дело до конца)» Я бы хотел, чтобы больше людей были настолько внимательны к использованию упорядоченных и неупорядоченных маркеров. Спасибо за ваш ответ.

2. @Красная горошина: одна из моих самых больших любимых HTML-мозолей: «В порядке от самого высокого / самого низкого до самого низкого / самого высокого:» за которым следует неупорядоченный список. Я имею в виду, давай, серьезно?

Ответ №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 мы хотим скрыть все элементы, имеющие класс rest.

В этом случае 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, css может быть таким

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

Комментарии:

1. Насколько это полезно для <tr> тегов?

Ответ №4:

Вот ваш ответ

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

Ответ №5:

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

Ответ №6:

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

Следующий 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;
}
 

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

Комментарии:

1. Я бы хотел поддержать это, но для этого нужна рабочая демонстрация.

2. Насколько я помню, на самом деле это было не так надежно, как казалось изначально — теперь я бы выбрал комментарий с самым высоким рейтингом, это невозможно.

Ответ №7:

ЕСЛИ у вас один и тот же родительский класс для всех селекторов, то вы используете этот класс 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>
 

Ответ №8:

Не ответ на вопрос «Может ли кто-нибудь объяснить, почему?», Поскольку другие ответы объяснили.

Но в качестве одного из возможных решений вашей ситуации вы можете использовать пользовательские теги для строк и ячеек, скажем <tr-row> , , <td-row> , тогда :nth-of-type() это должно сработать. Не забудьте установить стиль display: table-row; и display: table-cell; , соответственно, заставить их работать как ячейки таблицы.