web-dev-qa-db-fra.com

Puis-je combiner: nth-child () ou: nth-de-type () avec un sélecteur arbitraire?

Existe-t-il un moyen de sélectionner chaque nième enfant qui correspond (ou ne correspond pas) à un sélecteur arbitraire ? Par exemple, je veux sélectionner chaque ligne de table impaire, mais dans un sous-ensemble de lignes:

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>

Mais :nth-child() semble simplement compter tous les éléments tr, qu’ils appartiennent ou non à la classe "row", je me retrouve donc avec l’élément one even "row" au lieu des deux recherchés . La même chose se passe avec :nth-of-type().

Quelqu'un peut-il expliquer pourquoi?

81
atanamir

C'est un problème très courant qui découle d'un malentendu sur le fonctionnement de :nth-child() et :nth-of-type(). Malheureusement, il n’existe pas encore de solution basée sur un sélecteur, car Selectors ne permet pas de faire correspondre le nième enfant correspondant à un sélecteur arbitraire basé sur un modèle tel que impair, pair ou même an+ba != 1 et b != 0. Cela va au-delà des sélecteurs de classe, pour attribuer des sélecteurs, des négations et des combinaisons plus complexes de sélecteurs simples.

La pseudo-classe :nth-child() compte les éléments parmi tous de leurs frères et sœurs sous le même parent. Il ne compte pas uniquement les frères et soeurs qui correspondent au reste du sélecteur. De même, la pseudo-classe :nth-of-type() compte les frères et sœurs partageant le même type d'élément, qui fait référence au nom de la balise en HTML et non au reste du sélecteur.

Cela signifie également que si tous les enfants du même parent sont du même type d'élément, par exemple dans le cas d'un corps de tableau dont les enfants uniques sont des éléments tr ou d'un élément de liste dont les enfants uniques sont des éléments li, alors :nth-child() et :nth-of-type() se comporter de manière identique, c'est-à-dire que chaque valeur de an+b, :nth-child(an+b) et :nth-of-type(an+b) correspondra au même ensemble d'éléments.

En fait, tous les sélecteurs simples dans un sélecteur composé donné, y compris les pseudo-classes telles que :nth-child() et :not(), fonctionnent indépendamment les uns des autres, plutôt que de regarder le sous-ensemble d'éléments qui correspondent du sélecteur.

Cela implique également que il n'y a pas de notion d'ordre parmi les sélecteurs simples au sein de chaque sélecteur composé1, ce qui signifie par exemple que les deux sélecteurs suivants sont équivalents:

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

Traduits en anglais, ils signifient tous les deux:

Sélectionnez n'importe quel élément tr qui correspond à toutes les conditions indépendantes suivantes:

  • c'est un enfant impair de son parent;
  • il a la classe "rangée"; et
  • c'est un descendant d'un élément table qui a la classe "myClass".

(vous remarquerez que j'utilise une liste non ordonnée ici, juste pour faire passer le message.)

Comme il n’existe actuellement aucune solution CSS pure, vous devez utiliser un script pour filtrer les éléments et appliquer les styles ou les noms de classes supplémentaires en conséquence. Par exemple, voici une solution de contournement courante utilisant jQuery (en supposant qu'un seul groupe de lignes est peuplé d'éléments tr dans la table):

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

Avec le CSS correspondant:

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

Si vous utilisez des outils de test automatisés tels que Selenium ou le traitement HTML avec des outils tels que lxml, bon nombre de ces outils permettent à XPath de constituer une alternative:

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

D'autres solutions utilisant différentes technologies sont laissées au lecteur. il ne s'agit que d'un bref exemple artificiel d'illustration.


Pour ce que cela vaut, il existe une proposition d'ajouter une extension à la notation :nth-child() au sélecteur de niveau 4 dans le but spécifique de sélectionner chaque nième enfant correspondant à un sélecteur donné.2

Le sélecteur par lequel filtrer les correspondances est fourni en tant qu'argument à :nth-child(), toujours en raison de la manière dont les sélecteurs fonctionnent indépendamment les uns des autres dans une séquence dictée par la syntaxe de sélecteur existante. Donc, dans votre cas, cela ressemblerait à ceci:

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

(Un lecteur astucieux remarquera tout de suite que cela devrait être plutôt :nth-child(odd of tr.row), puisque les sélecteurs simples tr et :nth-child() fonctionnent également indépendamment l'un de l'autre. C'est l'un des problèmes des pseudo-classes fonctionnelles acceptant les sélecteurs, une boîte de Pandore Je préférerais ne pas ouvrir au milieu de cette réponse, mais plutôt supposer que la plupart des sites n'auront pas d'autres éléments que des éléments tr en tant que frères et soeurs les uns des autres dans un corps de tableau. fonctionnellement équivalent.)

Bien sûr, étant une toute nouvelle proposition dans une toute nouvelle spécification, sa mise en œuvre ne sera probablement mise en œuvre que dans quelques années. En attendant, vous devrez vous en tenir à un script, comme ci-dessus.


1Si vous spécifiez un type ou un sélecteur universel, il doit d'abord être utilisé. Cela ne change toutefois pas le fonctionnement fondamental des sélecteurs. ce n'est rien de plus qu'une bizarrerie syntaxique.

2Ceci a été proposé à l'origine comme :nth-match(); cependant, comme il compte toujours un élément relatif uniquement à ses frères et sœurs, et non à tous les autres éléments qui correspondent au sélecteur donné, il a depuis été transformé en extension à la :nth-child() existante.

105
BoltClock

Pas vraiment..

citation de la documentation

La pseudo-classe :nth-child correspond à un élément qui a un + b-1 frères/soeurs avant dans l'arborescence de documents, pour un étant donné une valeur positive ou nulle pour n, et a un élément parent.

C'est un sélecteur qui lui est propre et qui ne se combine pas avec les classes. Dans votre règle, il suffit de satisfaire les deux sélecteurs en même temps. Par conséquent, les lignes de la table :nth-child(even) seront affichées si elles ont également la classe .row.

6

nth-of-type fonctionne selon l'index du même type d'élément, mais nth-child fonctionne uniquement selon l'index, quel que soit le type des éléments frères.

Par exemple

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

Supposons qu'en HTML, nous voulions masquer tous les éléments ayant une classe de repos.

Dans ce cas, nth-child et nth-of-type fonctionneront exactement de la même manière, car tous les éléments sont du même type que <div> et css doit donc l'être.

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

Vous devez maintenant vous demander quelle est la différence entre nth-child et nth-of-type, donc voici la différence

Supposons que le HTML soit 

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

Dans le code HTML ci-dessus, le type d'élément .rest est différent des autres. .rest sont des paragraphes et d'autres sont div. Dans ce cas, si vous utilisez nth-child, vous devez écrire comme ceci

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

mais si vous utilisez nth-of-type css peut être ceci

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

Comme le type d'élément .rest est <p>, alors ici nth-of-type détecte le type de .rest, puis il a appliqué css aux 1er, 2ème, 3ème, 4ème, 5ème éléments de <p>.

0
Gaurav Aggarwal

Vous pourrez peut-être faire cela avec xpath. quelque chose comme //tr[contains(@class, 'row') and position() mod 2 = 0] pourrait fonctionner. Il y a d'autres SO questions développant les détails pour faire correspondre les classes plus précisément.

0
the8472

Voici votre réponse

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