CSS peut-il détecter le nombre d'enfants d'un élément?

304

Je réponds probablement à ma propre question, mais je suis extrêmement curieux.

Je sais que CSS peut sélectionner des enfants individuels d'un parent, mais existe-t-il un support pour styliser les enfants d'un conteneur, si son parent a une certaine quantité d'enfants.

par exemple

container:children(8) {
  // style the parent this way if there are 8 children
}

Je sais que ça semble bizarre, mais mon manager m'a demandé de le vérifier, je n'ai rien trouvé par moi-même alors j'ai décidé de me tourner vers SO avant de terminer la recherche.

Brodie
la source
2
Requête de quantité Mixte SCSS
Jakob E

Réponses:

695

Clarification:

En raison d'une formulation précédente de la question initiale, quelques citoyens de SO ont exprimé leur inquiétude quant à la possibilité que cette réponse soit trompeuse. Notez que, dans CSS3, les styles ne peuvent pas être appliqués à un nœud parent en fonction du nombre d'enfants qu'il possède. Cependant, les styles peuvent être appliqués aux nœuds enfants en fonction du nombre de frères et sœurs qu'ils ont.


Réponse originale:

Incroyablement, cela est désormais possible uniquement en CSS3.

/* one item */
li:first-child:nth-last-child(1) {
/* -or- li:only-child { */
    width: 100%;
}

/* two items */
li:first-child:nth-last-child(2),
li:first-child:nth-last-child(2) ~ li {
    width: 50%;
}

/* three items */
li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li {
    width: 33.3333%;
}

/* four items */
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
    width: 25%;
}

L'astuce consiste à sélectionner le premier enfant alors qu'il est également le nième du dernier enfant. Cela sélectionne efficacement en fonction du nombre de frères et sœurs.

Le mérite de cette technique revient à André Luís (découvert) et Lea Verou (raffinée).

N'aimez-vous pas simplement CSS3? 😄

Exemple CodePen:

Sources:

Matthemattics
la source
7
Très utile. J'ai écrit un mixin SASS qui utilise cette technique: codepen.io/anon/pen/pJeLdE?editors=110
SimpleJ
1
@IanSteffy Je viens de tester cela sur Chrome 45.0.2454.85 (64 bits) et ça fonctionne bien…?
Matthemattics
2
Si cela fonctionne dans codepen mais pas avec mon projet, c'est certainement ma faute. Ma faute. Cette réponse est correcte! C'est vrai, je dis!
Ian S
3
Pourrait être agréable d'ajouter pourquoi cela fonctionne, pour les personnes non habituées à plusieurs pseudo-sélecteurs (comme je l'étais jusqu'à présent;). Ce qui se passe ici, c'est que cela sélectionne l'enfant qui est à la fois l'enfant x du début / haut et l'enfant y de la fin. Et donc cela ne sélectionne quelque chose que s'il y a exactement x + y enfants.
Legolas
7
Notez qu'au lieu de :first-child:nth-last-child(1)vous pouvez également utiliser :only-child.
Adam Reis
40

Non, pas vraiment. Il y a quelques sélecteurs qui peuvent vous rapprocher un peu, mais ne fonctionneront probablement pas dans votre exemple et n'ont pas la meilleure compatibilité de navigateur.

:only-child

Le :only-childest l'un des rares vrais sélecteurs de comptage dans le sens où il n'est appliqué que lorsqu'il y a un enfant du parent de l'élément. En utilisant votre exemple idéalisé, il agit comme le children(1)ferait probablement.

:nth-child

Le :nth-childsélecteur peut vous amener où vous voulez aller en fonction de ce que vous cherchez vraiment à faire. Si vous voulez styliser tous les éléments s'il y a 8 enfants, vous n'avez pas de chance. Si, toutefois, vous souhaitez appliquer des styles au 8e et aux éléments ultérieurs, essayez ceci:

p:nth-child( n + 8 ){
    /* add styles to make it pretty */
}

Malheureusement, ce ne sont probablement pas les solutions que vous recherchez. En fin de compte, vous devrez probablement utiliser un peu de magie Javascript pour appliquer les styles en fonction du nombre - même si vous deviez utiliser l'un d'entre eux, vous auriez besoin de jeter un œil attentif à la compatibilité du navigateur avant de partir avec un pur Solution CSS.

W3 CSS3 Spec sur les pseudo-classes

EDIT J'ai lu votre question un peu différemment - il y a deux autres façons de styliser le parent , pas les enfants. Permettez-moi de lancer quelques autres sélecteurs à votre façon:

:empty et :not

Cela style les éléments qui n'ont pas d'enfants. Pas très utile en soi, mais lorsqu'il est associé au :notsélecteur, vous ne pouvez styliser que les éléments qui ont des enfants:

div:not(:empty) {
    /* We know it has stuff in it! */
}

Vous ne pouvez pas compter le nombre d'enfants disponibles avec du CSS pur ici, mais c'est un autre sélecteur intéressant qui vous permet de faire des choses intéressantes.

derekerdmann
la source
Il convient de noter la question initiale a été modifiée, ce qui rend la première « Non » un peu trompeur (juste FYI 😛)
Matthemattics
18

REMARQUE: cette solution retournera les enfants d'ensembles de certaines longueurs, pas l'élément parent comme vous l'avez demandé. J'espère que c'est toujours utile.

Andre Luis a proposé une méthode: http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/ Malheureusement, cela ne fonctionne que dans IE9 et au-dessus.

Essentiellement, vous combinez: nth-child () avec d'autres pseudo-classes qui traitent de la position d'un élément. Cette approche vous permet de spécifier des éléments à partir d' ensembles d'éléments de longueurs spécifiques .

Par exemple, :nth-child(1):nth-last-child(3)correspond au premier élément d'un ensemble tout en étant le troisième élément à partir de la fin de l'ensemble. Cela fait deux choses: garantit que l'ensemble n'a que trois éléments et que nous avons le premier des trois. Pour spécifier le deuxième élément de l'ensemble de trois éléments, nous utiliserions :nth-child(2):nth-last-child(2).


Exemple 1 - Sélectionnez tous les éléments de la liste si l'ensemble comporte trois éléments:

li:nth-child(1):nth-last-child(3),
li:nth-child(2):nth-last-child(2),
li:nth-child(3):nth-last-child(1) {
    width: 33.3333%;
}

Exemple 1 alternative de Lea Verou:

li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li {
    width: 33.3333%;
}


Exemple 2 - cible le dernier élément de l'ensemble avec trois éléments de liste:

li:nth-child(3):last-child {
    /* I'm the last of three */
}

Exemple 2 alternative:

li:nth-child(3):nth-last-child(1) {
    /* I'm the last of three */
}


Exemple 3 - cible le deuxième élément de l'ensemble avec quatre éléments de liste:

li:nth-child(2):nth-last-child(3) {
    /* I'm the second of four */
}
ifugu
la source
1
encore une fois, c'est le nombre de frères et sœurs, pas d'enfants
TMS
@TMS voir l'édition de la réponse acceptée - la question du PO a été maladroitement formulée
ifugu
Cette approche est parfaite lorsque chaque élément doit être stylisé différemment en fonction de sa position dans la liste, par exemple pour obtenir des transformations circulaires égales: li:nth-child(3):nth-last-child(1) { transform: rotate(120deg); } li:nth-child(2):nth-last-child(2) { transform: rotate(240deg); }et ainsi de suite ...
Greg Smith
11

En travaillant sur la solution de Matt, j'ai utilisé l'implémentation Compass / SCSS suivante.

@for $i from 1 through 20 {
    li:first-child:nth-last-child( #{$i} ),
    li:first-child:nth-last-child( #{$i} ) ~ li {
      width: calc(100% / #{$i} - 10px);
    }
  }

Cela vous permet d'augmenter rapidement le nombre d'articles.

mwtidd
la source
4
Au lieu de cela, vous pouvez facilement utiliser Flexbox…
Michał Miszczyszyn
6

oui, nous pouvons le faire en utilisant n-enfant comme si

div:nth-child(n + 8) {
    background: red;
}

Cela fera que le 8ème enfant div deviendra rouge. J'espère que cela t'aides...

De plus, si quelqu'un dit jamais "hé, ils ne peuvent pas être faits avec du style en utilisant CSS, utilisez JS !!!" en douter immédiatement. CSS est extrêmement flexible de nos jours

Exemple :: http://jsfiddle.net/uWrLE/1/

Dans l'exemple, les 7 premiers enfants sont bleus, puis 8 sont rouges ...

AlanFoster
la source
1
Peut-être ajouter une note sur le malheureux manque de soutien ?
benesch
2
Je ne pense pas que c'est exactement ce que Brodie demande - cela stylisera les enfants après un montant donné, mais ne peut pas sélectionner l'élément ancêtre / contenant en fonction du nombre de ses enfants.
Ben Hull
Ceci est en fait une assez bonne information cependant, merci Alan mais l'abeille a raison, j'essayais de dire "si un élément a autant d'enfants nous ce style" Si je ne me trompe pas, votre méthode coifferait le 8ème enfant, mais le les 7 premiers seraient solitaires et nus.
Brodie
@primatology - Le seul navigateur qui ne prend pas en charge nth-child est IE <9. Tous les autres l'ont supporté deux versions en arrière ou plus.
Rob
-1 Cela ne rendra pas le div enfant rouge, cela rendra le div rouge en fonction de son nombre dans ses frères et sœurs ! N'est pas lié à l'enfant de div en aucune façon!
TMS
5

Si vous allez le faire en CSS pur (en utilisant scss) mais que vous avez différents éléments / classes dans la même classe parent, vous pouvez utiliser cette version !!

  &:first-of-type:nth-last-of-type(1) {
    max-width: 100%;
  }

  @for $i from 2 through 10 {
    &:first-of-type:nth-last-of-type(#{$i}),
    &:first-of-type:nth-last-of-type(#{$i}) ~ & {
      max-width: (100% / #{$i});
    }
  }
Juan Sebastian Contreras Aceve
la source
-1

Non, il n'y a rien de tel en CSS. Vous pouvez cependant utiliser JavaScript pour calculer le nombre d'enfants et appliquer des styles.

Niet l'Absolu Noir
la source
1
@ Lübnah Pouvez-vous expliquer pourquoi ce n'est pas vrai?
Gabriel Santos