Posso combinar: nth-child () ou: nth-of-type () com um seletor arbitrário?

116

Existe uma maneira de selecionar cada enésimo filho que corresponda (ou não corresponda) a um seletor arbitrário ? Por exemplo, quero selecionar cada linha ímpar da tabela, mas dentro de um subconjunto das linhas:

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>

Mas :nth-child()parece contar todos os trelementos independentemente de serem ou não da classe "linha", então acabo com um elemento par "linha", em vez dos dois que estou procurando. A mesma coisa acontece com :nth-of-type().

Alguém pode explicar por quê?

atanamir
fonte

Respostas:

144

Este é um problema muito comum que surge devido a um mal-entendido sobre como :nth-child()e como :nth-of-type()funcionam. Infelizmente, não há atualmente nenhuma solução baseada em seletor ainda porque Seletores não fornecem uma maneira de corresponder ao enésimo filho que corresponde a um seletor arbitrário com base em um padrão como número ímpar, número par ou qualquer an+bonde a != 1e b != 0. Isso vai além de apenas seletores de classe, para atribuir seletores, negações e combinações mais complexas de seletores simples.

A :nth-child()pseudo classe conta elementos entre todos os seus irmãos sob o mesmo pai. Ele não conta apenas os irmãos que correspondem ao resto do seletor. Da mesma forma, a :nth-of-type()pseudo classe conta irmãos que compartilham o mesmo tipo de elemento, que se refere ao nome da tag em HTML, e não ao resto do seletor.

Isso também significa que se todos os filhos do mesmo pai são do mesmo tipo de elemento, por exemplo, no caso de um corpo de tabela cujos únicos filhos são trelementos ou um elemento de lista cujos únicos filhos são lielementos, então :nth-child()e :nth-of-type()se comportarão de forma idêntica, ou seja, para cada valor de an+b, :nth-child(an+b)e :nth-of-type(an+b)irá coincidir com o mesmo conjunto de elementos.

Na verdade, todos os seletores simples em um determinado seletor composto, incluindo pseudoclasses como :nth-child()e :not(), funcionam independentemente uns dos outros, em vez de olhar para o subconjunto de elementos que são correspondidos pelo resto do seletor.

Isso também implica que não há noção de ordem entre os seletores simples dentro de cada seletor composto individual 1 , o que significa, por exemplo, os dois seletores a seguir são equivalentes:

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

Traduzido para o inglês, ambos significam:

Selecione qualquer trelemento que corresponda a todas as seguintes condições independentes:

  • é um filho de número ímpar de seu pai;
  • tem a classe "linha"; e
  • é um descendente de um tableelemento que possui a classe "myClass".

(você notará meu uso de uma lista não ordenada aqui, apenas para esclarecer o ponto)

Como atualmente não existe uma solução CSS pura, você terá que usar um script para filtrar elementos e aplicar estilos ou nomes de classes extras de acordo. Por exemplo, o seguinte é uma solução alternativa comum usando jQuery (assumindo que haja apenas um grupo de linhas preenchido com trelementos na tabela):

$('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');
});

Com o CSS correspondente:

table.myClass tr.row.odd {
  ...
}

Se você estiver usando ferramentas de teste automatizadas, como Selenium ou processamento de HTML com ferramentas como lxml, muitas dessas ferramentas permitem XPath como alternativa:

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

Outras soluções usando tecnologias diferentes são deixadas como um exercício para o leitor; este é apenas um exemplo breve e planejado para ilustração.


Pelo que vale a pena, há uma proposta de extensão da :nth-child()notação a ser adicionada aos Seletores de nível 4 com o propósito específico de selecionar cada enésimo filho que corresponda a um determinado seletor.2

O seletor pelo qual filtrar correspondências é fornecido como um argumento :nth-child(), novamente devido à forma como os seletores operam independentemente um do outro em uma sequência, conforme ditado pela sintaxe do seletor existente. Portanto, no seu caso, seria assim:

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

(Um leitor astuto notará imediatamente que deveria ser assim :nth-child(odd of tr.row), uma vez que os seletores simples tre :nth-child()operam independentemente uns dos outros também. Este é um dos problemas com pseudo classes funcionais que aceitam seletores, uma lata de vermes que eu em vez de não abrir no meio desta resposta. Em vez disso, partirei do pressuposto de que a maioria dos sites não terá nenhum outro elemento além de trelementos como irmãos um do outro no corpo de uma tabela, o que tornaria qualquer uma das opções funcionalmente equivalente.)

Obviamente, sendo uma proposta totalmente nova em uma especificação totalmente nova, isso provavelmente não terá implementação até alguns anos depois. Nesse ínterim, você terá que continuar usando um script, como acima.


1 Se você especificar um tipo ou seletor universal, ele deve vir primeiro. Isso não muda a maneira como os seletores funcionam fundamentalmente; não é nada mais do que uma peculiaridade sintática.

2 Isso foi originalmente proposto porque :nth-match(), no entanto, porque ainda conta um elemento relativo apenas a seus irmãos, e não a todos os outros elementos que correspondem ao seletor fornecido, desde 2014 foi reaproveitado como uma extensão do existente :nth-child().

BoltClock
fonte
3
"(você notará meu uso de uma lista não ordenada aqui, apenas para esclarecer o ponto)" Gostaria que mais pessoas fossem tão deliberadas sobre o uso de balas ordenadas versus não ordenadas. Obrigado pela sua resposta.
The Red Pea
1
@ The Red Pea: Um dos meus maiores aborrecimentos de HTML: "Em ordem do mais alto / mais baixo para o mais baixo / mais alto:" seguido por uma lista não ordenada. Quer dizer, vamos, sério?
BoltClock
6

Na verdade não..

citação dos documentos

A :nth-childpseudoclasse corresponde a um elemento que tem + b-1 irmãos antes dele na árvore do documento , para um determinado valor positivo ou zero para n, e tem um elemento pai.

É um seletor próprio e não combina com classes. Em sua regra, ele apenas precisa satisfazer os dois seletores ao mesmo tempo, portanto, ele mostrará as :nth-child(even)linhas da tabela se elas também tiverem a .rowclasse.

Gabriele Petrioli
fonte
0

nth-of-type funciona de acordo com o índice do mesmo tipo do elemento, mas nth-child funciona apenas de acordo com o índice, independentemente do tipo de elementos irmãos.

Por exemplo

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

Suponha que no html acima desejamos ocultar todos os elementos com a classe restante.

Neste caso nth-childe nth-of-typevai funcionar exatamente o mesmo que todo o elemento são do mesmo tipo que é <div>tão css deve ser

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

OU

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

Agora você deve estar se perguntando qual é a diferença entre nth-childenth-of-type esta é a diferença

Suponha que o html seja

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

No html acima o tipo de .restelemento é diferente dos outros .restsão parágrafos e os outros são div então neste caso se você usar nth-childvocêterá de escrever assim

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

mas se você usar o css do enésimo tipo pode ser este

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

Como tipo de .restelemento é <p>assim aqui nth-of-typeestá detectando o tipo de .reste então aplicou css no 1º, 2º, 3º, 4º, 5º elemento de <p>.

Gaurav Aggarwal
fonte
Isso é útil para <tr>tags?
Alexis Wilke
0

Você pode fazer isso com o xpath. algo como //tr[contains(@class, 'row') and position() mod 2 = 0]pode funcionar. Existem outras questões do SO expandindo os detalhes de como combinar as classes com mais precisão.

the8472
fonte
0

Aqui está sua resposta

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

Todas as perguntas sobre o uso de nth-child e pular tags ocultas parecem estar redirecionando como ingênuas desta, então vou deixar isso aqui. Encontrei este blog https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/ que usa uma abordagem css inteligente para fazer com que o nth-child ignore os elementos ocultos, do seguinte modo:

O CSS a seguir adiciona uma margem direita a cada segundo elemento visível, não importa qual elemento tenha a classe 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;
}

Espero que ajude alguém que está seguindo o mesmo caminho para as questões de ignorar elementos ocultos!

IrishDubGuy
fonte
1
Eu gostaria de votar a favor, mas precisa de uma demonstração funcional.
Moob
Minha lembrança é que isso não era realmente tão robusto quanto parecia inicialmente - eu agora escolheria o comentário mais votado, isso não é possível.
IrishDubGuy
0

SE você tiver a mesma classe pai para todos os seletores, então você usa essa classe document.querySelector("main .box-value:nth-child(3) select.priorityOption"); porque nesse caso document.querySelector("main .box-value select.priorityOption:nth-child(3)");não funciona. Obrigado

<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>
Jatin Aggarwal
fonte