Appliquer des styles CSS à un élément en fonction de ses éléments enfants

203

Est-il possible de définir un style CSS pour un élément, qui n'est appliqué que si l'élément correspondant contient un élément spécifique (comme l'élément enfant direct)?

Je pense que cela s'explique mieux à l'aide d'un exemple.

Remarque : J'essaie de styliser l'élément parent , en fonction des éléments enfants qu'il contient.

<style>
  /* note this is invalid syntax. I'm using the non-existing
   ":containing" pseudo-class to show what I want to achieve. */
  div:containing div.a { border: solid 3px red; }
  div:containing div.b { border: solid 3px blue; }
</style>

<!-- the following div should have a red border because
     if contains a div with class="a" -->
<div>
  <div class="a"></div>
</div>

<!-- the following div should have a blue border -->
<div>
  <div class="b"></div>
</div>

Note 2 : Je sais que je peux y arriver en utilisant javascript, mais je me demandais simplement si cela était possible en utilisant des fonctionnalités CSS inconnues (pour moi).

M4N
la source
1
Vous pouvez mettre à jour la question pour indiquer, peut-être avec un texte en gras clignotant, que vous essayez de styliser la div PARENT, pas ses enfants. Je sais que l'information est dans la question elle-même, mais à moins que vous ne vouliez obtenir une tonne de réponses incorrectes, cela en vaut probablement la peine.
Seth Petry-Johnson
Merci @Seth. J'ai essayé d'améliorer le titre et le texte de la question. Veuillez modifier la question si vous pensez qu'elle n'est toujours pas claire.
M4N
3
doublon possible de Y a
James Donnelly
Ceci est l'exemple parfait de la raison pour laquelle ce type de support en CSS serait idéal: ol < li:nth-child(n+10) { margin-left: 2rem; } ol < li:nth-child(n+100) { margin-left: 3rem; } ol < li:nth-child(n+1000) { margin-left: 4rem; }dans un monde idéal, cela augmenterait la marge de la olpersonne à charge en fonction du nombre d' lienfants contenus afin que la marge de gauche ne soit aussi large qu'elle devait être.
Jonmark Weber

Réponses:

124

À ma connaissance, le style d'un élément parent basé sur l'élément enfant n'est pas une fonctionnalité disponible de CSS. Vous aurez probablement besoin de scripts pour cela.

Ce serait merveilleux si vous pouviez faire quelque chose comme div[div.a]ou div:containing[div.a]comme vous l'avez dit, mais ce n'est pas possible.

Vous voudrez peut-être envisager de regarder jQuery . Ses sélecteurs fonctionnent très bien avec les types «contenant». Vous pouvez sélectionner le div, en fonction de son contenu enfant, puis appliquer une classe CSS au parent sur une seule ligne.

Si vous utilisez jQuery, quelque chose du genre pourrait fonctionner (non testé mais la théorie est là):

$('div:has(div.a)').css('border', '1px solid red');

ou

$('div:has(div.a)').addClass('redBorder');

combiné avec une classe CSS:

.redBorder
{
    border: 1px solid red;
}

Voici la documentation du sélecteur jQuery "has" .

KP.
la source
15
Note latérale: pour de meilleures performances, la page de documentation jQuery pour le :hassélecteur conseille d'utiliser la .has()méthode ( api.jquery.com/has ) => appliquée à la question actuelle qu'elle donnerait par exemple$('div').has('div.a').css('border', '1px solid red');
Frosty Z
Pour que cela fonctionne, il faudrait utiliser l'observateur de mutation, pour vérifier si l'enfant a changé son état ...
Legends
Cela ne répond pas vraiment à la question qui est "Y a-t-il un moyen de le faire avec CSS". Il indique clairement: "Je sais que je peux y parvenir en utilisant javascript, mais je me demandais simplement si cela était possible en utilisant des fonctionnalités CSS inconnues (pour moi)."
SunshinyDoyle
developer.mozilla.org/en-US/docs/Web/CSS/:has , je pense que ce :hassélecteur peut fonctionner mais il est en version préliminaire et aucun navigateur ne le prend en charge.
AliF50
62

En gros, non. Ce qui suit serait être ce que vous étiez après en théorie:

div.a < div { border: solid 3px red; }

Malheureusement ça n'existe pas.

Il y a quelques articles sur le thème "pourquoi diable pas". Un bien étoffé par Shaun Inman est assez bon:

http://www.shauninman.com/archive/2008/05/05/css_qualified_selectors

Justin Wignall
la source
34
juste une mise à jour 8 ans plus tard: il n'y a toujours pas de support pour cette méthode de sélection.
Kraang Prime
1
Il existe un brouillon de travail pour cette fonctionnalité sous la forme d'une :has()pseudo-classe, mais nous ne pourrons l'utiliser que dans CSS4. À ce jour (fin 2019), JS est toujours le seul moyen d'atteindre cette fonctionnalité.
zepp.lee
Je crois que cela n'activera pas les styles CSS, il faudra quand même du javascript pour utiliser le sélecteur. A moins que cela n'ait changé?
Justin Wignall
3
9 ans et pensent-ils que cette fonctionnalité est inutile?
Loi Nguyen Huynh
1

En plus de la réponse de @ kp:

Je m'occupe de cela et dans mon cas, je dois montrer un élément enfant et corriger la hauteur de l'objet parent en conséquence (le dimensionnement automatique ne fonctionne pas dans un en-tête de démarrage pour une raison quelconque, je n'ai pas le temps de déboguer) .

Mais au lieu d'utiliser javascript pour modifier le parent, je pense que je vais ajouter dynamiquement une classe CSS au parent et CSS-sélectivement montrer les enfants en conséquence. Cela maintiendra les décisions dans la logique et non sur la base d'un état CSS.

tl; dr; appliquer les styles aet bau parent <div>, pas à l'enfant (bien sûr, tout le monde ne pourra pas le faire. Par exemple, les composants angulaires prennent leurs propres décisions).

<style>
  .parent            { height: 50px; }
  .parent div        { display: none; }
  .with-children     { height: 100px; }
  .with-children div { display: block; }
</style>

<div class="parent">
  <div>child</div>
</div>

<script>
  // to show the children
  $('.parent').addClass('with-children');
</script>
Mauricio Morales
la source
0

Dans mon cas, j'ai dû changer le remplissage des cellules d'un élément qui contenait une case à cocher d'entrée pour un tableau qui est rendu dynamiquement avec DataTables:

<td class="dt-center">
    <input class="a" name="constCheck" type="checkbox" checked="">
</td>

Après avoir implémenté le code de ligne suivant dans la fonction initComplete , j'ai pu produire le rembourrage correct, ce qui a empêché l' affichage des lignes avec une hauteur anormalement grande

 $('tbody td:has(input.a)').css('padding', '0px');

Maintenant, vous pouvez voir que les styles corrects sont appliqués à l'élément parent:

<td class=" dt-center" style="padding: 0px;">
    <input class="a" name="constCheck" type="checkbox" checked="">
</td>

Essentiellement, cette réponse est une extension de la réponse de @ KP, mais plus il y a de collaboration pour l'implémenter, mieux c'est. En résumé, j'espère que cela aide quelqu'un d'autre car cela fonctionne! Enfin, merci beaucoup @KP de m'avoir conduit dans la bonne direction!

miles
la source