Comment affecter d'autres éléments lorsqu'un élément est survolé

459

Ce que je veux faire, c'est quand un certain divsurvole, cela affecterait les propriétés d'un autre div.

Par exemple, dans cette démo JSFiddle , lorsque vous survolez , #cubecela change le background-colormais ce que je veux, c'est que lorsque je survole #container, #cubeest affecté.

div {
  outline: 1px solid red;
}
#container {
  width: 200px;
  height: 30px;
}
#cube {
  width: 30px;
  height: 100%;
  background-color: red;
}
#cube:hover {
  width: 30px;
  height: 100%;
  background-color: blue;
}
<div id="container">

  <div id="cube">
  </div>

</div>

Trufa
la source

Réponses:

987

Si le cube est directement à l'intérieur du conteneur:

#container:hover > #cube { background-color: yellow; }

Si le cube se trouve à côté (après la fermeture des conteneurs de la balise) du conteneur:

#container:hover + #cube { background-color: yellow; }

Si le cube se trouve quelque part à l'intérieur du conteneur:

#container:hover #cube { background-color: yellow; }

Si le cube est un frère du conteneur:

#container:hover ~ #cube { background-color: yellow; }
Mike
la source
107
N'oubliez pas le combinateur général de frères et sœurs ~pour «le cube est quelque part après le conteneur dans le DOM et partage un parent»
robertc
3
C'est plutôt cool. Y a-t-il une source où je peux trouver plus d'informations à ce sujet? Est-il pris en charge par tous les navigateurs, est-ce CSS3? Ce serait formidable d'avoir plus d'informations à ce sujet. Merci beaucoup!
Anonyme
2
+1 Excellente réponse @Mike. Et si #containerest à côté #cube, c'est- à -dire #containersuit #cube?
PeterKA
4
Que faire si l'élément survolé se trouve à l'intérieur du conteneur (que nous voulons effectuer) ??? Par exemple: #cube: hover #container {Quelques effets CSS}
Hanzallah Afgan
2
Bonne réponse !! Et si je veux changer de parent lorsque je survole l'enfant. Je pense qu'il n'y a pas de sélecteur pour cela.
Mikel
41

Dans cet exemple particulier, vous pouvez utiliser:

#container:hover #cube {
    background-color: yellow;   
}

Cet exemple ne fonctionne que depuis qu'il cubeest un enfant de container. Pour des scénarios plus compliqués, vous devez utiliser un CSS différent ou utiliser JavaScript.

Emmett
la source
35

L'utilisation du sélecteur frère est la solution générale pour styliser d'autres éléments lorsque vous survolez un élément donné, mais cela ne fonctionne que si les autres éléments suivent l'élément donné dans le DOM . Que pouvons-nous faire alors que les autres éléments devraient être réellement avant celui plané? Supposons que nous souhaitons implémenter un widget d'évaluation de la barre de signal comme celui ci-dessous:

Widget de notation de la barre de signal

Cela peut en fait être fait facilement en utilisant le modèle CSS flexbox, en définissant flex-directionsur reverse, de sorte que les éléments soient affichés dans l'ordre inverse de celui dans lequel ils se trouvent dans le DOM. La capture d'écran ci-dessus provient d'un tel widget, implémenté avec du CSS pur.

Flexbox est très bien supporté par 95% des navigateurs modernes.

Dan Dascalescu
la source
Cela pourrait-il être modifié pour que la surbrillance ne disparaisse pas lorsque vous déplacez la souris d'une barre à l'autre? Le clignotement est un peu gênant.
Cerbrus
@Cerbrus: Ajout d'une solution qui ne masque pas le survol lorsque la souris se trouve entre les barres. L'inconvénient est que la largeur des barres n'est plus égale.
Dan Dascalescu
1
Essayez ceci dans votre premier extrait: sur .rating div, supprimez la marge et ajoutezborder-right: 4px solid white;
Cerbrus
1
Flex direction (pas bien pris en charge pour IE) OU 1) noir par défaut 2) tout bleu sur la souris sur le conteneur 3) noir pour le prochain frère sur la barre en vol stationnaire :)
Stephane Mathis
J'ai fait ce violon qui (au moins pour moi) l'a rendu un peu plus apparenté à ce qui se passait ici. jsfiddle.net/maxshuty/cj55y33p/3
maxshuty
8

Un grand merci à Mike et Robertc pour leurs messages utiles!

Si vous avez deux éléments dans votre code HTML et que vous souhaitez en :hoversuperposer un et cibler un changement de style dans l'autre, les deux éléments doivent être directement liés - parents, enfants ou frères et sœurs. Cela signifie que les deux éléments doivent être l'un dans l'autre ou doivent tous deux être contenus dans le même élément plus grand.

Je voulais afficher les définitions dans une boîte sur le côté droit du navigateur pendant que mes utilisateurs lisent mon site et les :hovertermes en surbrillance; par conséquent, je ne voulais pas que l'élément 'definition' soit affiché à l'intérieur de l'élément 'text'.

J'ai presque abandonné et j'ai juste ajouté du javascript à ma page, mais c'est le futur, dang it! Nous ne devrions pas avoir à supporter le dos sass de CSS et HTML nous disant où nous devons placer nos éléments pour obtenir les effets que nous voulons! En fin de compte, nous avons compromis.

Bien que les éléments HTML réels du fichier doivent être imbriqués ou contenus dans un seul élément pour être des :hovercibles valides les uns aux autres, l' positionattribut css peut être utilisé pour afficher n'importe quel élément où vous le souhaitez. J'ai utilisé position: fixed pour placer la cible de mon :hoveraction là où je la voulais sur l'écran de l'utilisateur quel que soit son emplacement dans le document HTML.

Le html:

<div id="explainBox" class="explainBox"> /*Common parent*/

  <a class="defP" id="light" href="http://en.wikipedia.or/wiki/Light">Light                            /*highlighted term in text*/
  </a> is as ubiquitous as it is mysterious. /*plain text*/

  <div id="definitions"> /*Container for :hover-displayed definitions*/
    <p class="def" id="light"> /*example definition entry*/ Light:
      <br/>Short Answer: The type of energy you see
    </p>
  </div>

</div>

Le css:

/*read: "when user hovers over #light somewhere inside #explainBox
    set display to inline-block for #light directly inside of #definitions.*/

#explainBox #light:hover~#definitions>#light {
  display: inline-block;
}

.def {
  display: none;
}

#definitions {
  background-color: black;
  position: fixed;
  /*position attribute*/
  top: 5em;
  /*position attribute*/
  right: 2em;
  /*position attribute*/
  width: 20em;
  height: 30em;
  border: 1px solid orange;
  border-radius: 12px;
  padding: 10px;
}

Dans cet exemple, la cible d'une :hovercommande à partir d'un élément à l'intérieur #explainBoxdoit être #explainBoxou également à l'intérieur #explainBox. Les attributs de position attribués à #definitions le forcent à apparaître à l'emplacement souhaité (extérieur #explainBox) même s'il est techniquement situé dans une position indésirable dans le document HTML.

Je comprends qu'il est considéré comme une mauvaise forme d'utiliser le même #idpour plus d'un élément HTML; cependant, dans ce cas, les instances de #lightpeuvent être décrites indépendamment en raison de leurs positions respectives dans #iddes éléments uniques . Y a-t-il une raison de ne pas répéter le id #lightdans ce cas?

meule
la source
Une réponse assez longue pour un point aussi court, mais en voici un jsfiddle jsfiddle.net/ubershmekel/bWgq6/1
ubershmekel
1
certains browers vont paniquer lorsque vous utilisez les mêmes IDplusieurs fois. Utilisez simplement un class.
Serj Sagan
6

Seulement cela a fonctionné pour moi:

#container:hover .cube { background-color: yellow; }

Où se .cubetrouve CssClass du #cube.

Testé dans Firefox , Chrome et Edge .

CyberHawk
la source
4

Voici une autre idée qui vous permet d'affecter d'autres éléments sans considérer de sélecteur spécifique et en utilisant uniquement l' :hoverétat de l'élément principal.

Pour cela, je m'appuierai sur l'utilisation de propriétés personnalisées (variables CSS). Comme nous pouvons le lire dans la spécification :

Les propriétés personnalisées sont des propriétés ordinaires , elles peuvent donc être déclarées sur n'importe quel élément, elles sont résolues avec les règles d' héritage et de cascade normales ...

L'idée est de définir des propriétés personnalisées au sein de l'élément principal et de les utiliser pour styliser les éléments enfants et puisque ces propriétés sont héritées, nous devons simplement les modifier dans l'élément principal en survol.

Voici un exemple:

#container {
  width: 200px;
  height: 30px;
  border: 1px solid var(--c);
  --c:red;
}
#container:hover {
  --c:blue;
}
#container > div {
  width: 30px;
  height: 100%;
  background-color: var(--c);
}
<div id="container">
  <div>
  </div>
</div>

Pourquoi cela peut-il être mieux que d'utiliser un sélecteur spécifique combiné avec le vol stationnaire?

Je peux fournir au moins 2 raisons qui font de cette méthode une bonne chose à considérer:

  1. Si nous avons de nombreux éléments imbriqués qui partagent les mêmes styles, cela nous évitera un sélecteur complexe pour tous les cibler en survol. En utilisant des propriétés personnalisées, nous modifions simplement la valeur lors du survol de l'élément parent.
  2. Une propriété personnalisée peut être utilisée pour remplacer une valeur de n'importe quelle propriété et également une valeur partielle de celle-ci. Par exemple , nous pouvons définir une propriété personnalisée pour une couleur et nous l' utilisons dans un border, linear-gradient, background-color, box-shadowetc. Cela nous évitera reseting toutes ces propriétés sur le vol stationnaire.

Voici un exemple plus complexe:

.container {
  --c:red;
  width:400px;
  display:flex;
  border:1px solid var(--c);
  justify-content:space-between;
  padding:5px;
  background:linear-gradient(var(--c),var(--c)) 0 50%/100% 3px no-repeat;
}
.box {
  width:30%;
  background:var(--c);
  box-shadow:0px 0px 5px var(--c);
  position:relative;
}
.box:before {
  content:"A";
  display:block;
  width:15px;
  margin:0 auto;
  height:100%;
  color:var(--c);
  background:#fff;
}

/*Hover*/
.container:hover {
  --c:blue;
}
<div class="container">
<div class="box"></div>
<div class="box"></div>
</div>

Comme nous pouvons le voir ci-dessus, nous n'avons besoin que d' une seule déclaration CSS pour changer de nombreuses propriétés de différents éléments.

Temani Afif
la source