#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;
, соответственно, заставить их работать как ячейки таблицы.