web-dev-qa-db-fra.com

Afficher le menu déroulant en survol et fermer au clic en utilisant uniquement CSS

Quelqu'un peut-il m'aider à comprendre pourquoi les liens d'un menu déroulant ne fonctionnent pas lorsque je clique dessus? Peut-être à cause d'événements de pointeur? J'essaie d'avoir un menu déroulant qui se ferme après avoir cliqué sur un lien ou cliqué sur le bouton de fermeture. J'ai ajouté des trucs sympas comme cacher le conteneur parent quand un lien est cliqué.

Il y a beaucoup d'options pour faire ça:

  1. en utilisant :focus, mais lorsque le focus est utilisé, la liste déroulante ne sera pas déclenchée lors du survol suivant.

  2. utiliser :active sur le conteneur et pointer-events pour ne pointer que les liens actifs active, mais les événements de pointeur sont erronés

  3. utiliser :target mais a le même problème que: focus, ne déclenchera pas le deuxième aspirateur.

body {
    padding: 20px;
}
.container {
    border: 1px solid Lime;
    padding: 10px;
    width: 200px;
}
.test1 {
    display: none;
    border: 1px dashed orange;
    background: green;
    padding: 10px;
    pointer-events: none;
}
.container:hover .test1 {
    display: inline-block;
}
.container:hover .test1:active {
    display: none;
}
a {
    pointer-events: auto;
    color: Lime;
    font-weight: bold;
}
<ul class="container">
	 Drop down menu
	<li class="test1">
	<a class="dropdown" href="#">X Close</a>
	<ul class="content">
		 CLOSE THIS CONTENT
		<li class="link"><a href="http://www.google.com">Go to link 1</a></li>
		<li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
		<li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
	</ul>

12
RulerNature

Vérification rapide: Travailler JSFiddle

Quelqu'un peut-il m'aider à comprendre pourquoi les liens d'un menu déroulant ne fonctionnent pas lorsque je clique dessus? Peut-être à cause d'événements de pointeur? 

Explication de la raison pour laquelle ce comportement: Oui, vous avez raison, c'est à cause de la façon dont vous utilisez la logique de sélecteur :active, Pour une explication détaillée, tenez compte de cette règle CSS.

.container:hover .test1:active {
    display: none;
}

Vous avez vos liens de menu sous votre li.test1 principal et tous les clics sur les liens internes sont également renvoyés vers cet élément, c’est aussi bon que de cliquer sur la li. Ainsi, dès que la souris est maintenue enfoncée (événement de souris enfoncé), l'événement :active est déclenché et vous masquez la variable links (c'est-à-dire: li.test1). Toutefois, un événement click n'est terminé que lorsque la souris est enfoncée haut et bas. Donc maintenant la li est cachée et le mouse up n'est plus sur le lien. Donc, comme vous le voyez, il n'y a aucune chance que l'événement click soit déclenché. C'est le problème.


I saw other answers which you seem to be interested in and this really doesn't need any kind of hack, It can be done by just formatting your HTML and with some CSS changes.


Solution: Plutôt que d'envelopper vos liens de menu internes dans le li.test1, vous pouvez travailler avec deux li différents, l'un pour le X CLose et l'autre pour contenir le menu links. Avec cela en place, nous pouvons nous assurer que chaque fois que le li.test1 est actif (c’est-à-dire que la souris est enfoncée), nous pouvons le masquer ainsi que l’autre nouvelle li qui lui est adjacente. Cela signifie donc que chaque fois que l'utilisateur clique sur la X Closeli, nous masquons le menu. S'il clique sur les autres éléments du menu, vous êtes redirigé.

Donc, les changements dans votre structure HTML devraient être comme

<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
  </li>
  <li class="MenuLinks">
    <ul class="content">
      <!-- all your links go here-->
    </ul>
  </li>
</ul>

Et la règle principale de CSS est 

.container:hover .test1:active,
.container:hover .test1:active + .MenuLinks {
  display: none;
}

Ci-dessous se trouve un SO extrait de travail

body {
  padding: 20px;
}
.container {
  border: 1px solid Lime;
  padding: 10px;
  width: 200px;
  list-style-type: none;
}
.test1,
.MenuLinks {  
  display: none;
  border-color: orange;
  border-style: dashed;
  background: green;
  pointer-events: none;
}
.test1 {
  padding: 10px;
  border-width: 1px 1px 0px 1px;
}
.MenuLinks {
  border-width: 0px 1px 1px 1px;
}
.container:hover li {
  display: block;
}

/*Rule to hide both test1 and MenuLinks when X Close is clicked*/
.container:hover .test1:active,
.container:hover .test1:active + .MenuLinks {
  display: none;
}


a {
  pointer-events: auto;
  color: Lime;
  font-weight: bold;
}
<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
  </li>
  <!--seperate li for close-->

  <li class="MenuLinks">
    <!--wrap all your menu items here-->
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
      </li>
    </ul>
    <li>
</ul>


Note: L'écran vide lorsque vous cliquez sur les liens est dû à la sécurité de Google. Restrictions sur la stratégie d'origine croisée qui donne cette erreur dans la console 

Refused to display 'https://www.google.co.in/?gfe_rd=cr&ei=x2VWWLL2Ae-K8Qfwx4ngDQ' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.

Cependant, vous pouvez voir les demandes dans l'onglet Réseau lorsque vous cliquez sur les liens.

J'espère que cela t'aides!!

3
Rajshekar Reddy

Je le ferais normalement en utilisant JS - mais avec CSS il est un hack:

Commencez par créer une entrée avec id close et une label pour ceci qui enveloppe notre bouton de fermeture:

  <input type="radio" id="close" />
  <li class="test1">
    <label for="close">
      <a class="dropdown" href="#">X Close</a>
    </label>

et ajoutez dans ce style au lieu du .test1:active actuel:

.container:hover #close:active + .test1{
  display: none;
}
#close {
  display: none;
}

Voir la démo ci-dessous:

body {
  padding: 20px;
}
.container {
  border: 1px solid Lime;
  padding: 10px;
  width: 200px;
}
.test1 {
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;
}
.container:hover .test1 {
  display: inline-block;
}
#close {
  display: none;
}
.container:hover #close:active + .test1 {
  display: none;
}
a {
  pointer-events: auto;
  color: Lime;
  font-weight: bold;
}
<ul class="container">
  Drop down menu
  <input type="radio" id="close" />
  <li class="test1">
    <label for="close">
      <a class="dropdown" href="#">X Close</a>
    </label>
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
      </li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
      </li>
    </ul>
  </li>
</ul>

Mais le code ci-dessus a un élément input invalide dans une ul - pour empêcher que vous puissiez éditer le balisage un peu pour créer un autre wrapper pour la ul (vous devez peut-être ajuster un peu la largeur/le bourrage en raison du changement de balisage) voir le code ci-dessous:

body {
  padding: 20px;
}
.container {
  border: 1px solid Lime;
  padding: 10px;
}
ul {
  width: 200px;
}
.test1 {
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;
}
.container:hover .test1 {
  display: inline-block;
}
#close {
  display: none;
}
.container:hover #close:active + ul > li.test1 {
  display: none;
}
a {
  pointer-events: auto;
  color: Lime;
  font-weight: bold;
}
<div class="container">
  Drop down menu
  <input type="radio" id="close" />
  <ul>
    <li class="test1">
      <label for="close">
        <a class="dropdown" href="#">X Close</a>
      </label>
      <ul class="content">
        CLOSE THIS CONTENT
        <li class="link"><a href="http://www.google.com">Go to link 1</a>
        </li>
        <li class="link"><a href="https://www.google.co.uk">Go to link 2</a>
        </li>
        <li class="link"><a href="https://www.google.co.uk">Go to link 3</a>
        </li>
      </ul>
    </li>
  </ul>
</div>

4
kukkuz

Vous pouvez utiliser label et button en place sur a pour fermer le lien et vous pouvez procéder de la manière suivante 

body {
  padding: 20px;
}

.container {
  border: 1px solid Lime;
  padding: 10px;
  width: 200px;
}

.test1 {
  display: none;
  border: 1px dashed orange;
  background: green;
  padding: 10px;
  pointer-events: none;
}

.container:hover .test1 {
  display: inline-block;
}

a, label {
  pointer-events: auto;
  color: Lime;
  font-weight: bold;
}

/* close button */
#xclose:active + .test1 {
  display:none;
}

#xclose {
  display: none;
}
<ul class="container">
  Drop down menu
  <button id="xclose">X close</button>
  <li class="test1">    
    <label class="dropdown" for="xclose">X Close</label>        
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </li>
</ul>

J'espère que cela vous aidera d'une manière (y).

1
pradeep1991singh

Je suggère de retirer

.container:hover .test1:active {
    display: none;
}

et trouvez un autre moyen (quelques lignes de javascript suffiront) de fermer le panneau lorsque vous cliquez sur le lien "Fermer". (A également corrigé quelques balises HTML manquantes). Maintenant les liens fonctionnent:

body {
    padding: 20px;
}
.container {
    border: 1px solid Lime;
    padding: 10px;
    width: 200px;
}
.test1 {
    display: none;
    border: 1px dashed orange;
    background: green;
    padding: 10px;
    pointer-events: none;
}
.container:hover .test1 {
    display: inline-block;
}
a {
    pointer-events: auto;
    color: Lime;
    font-weight: bold;
}
<ul class="container">
  Drop down menu
  <li class="test1">
    <a class="dropdown" href="#">X Close</a>
    <ul class="content">
      CLOSE THIS CONTENT
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </li>
</ul>

1
Theodore K.

Cela ne semble pas fonctionner, car la souris :hover- pour garder le menu déroulant est disparue. Ainsi, l'événement de souris en haut n'est pas exécuté sur le lien car la liste déroulante est déjà fermée à nouveau. Aucun clic n'est donc effectué. Vous devez utiliser javascript pour ouvrir et fermer le menu déroulant.

1
Martin Cup

En CSS, vous pouvez lier les éléments label à inputs. Dans ce cas, vous pouvez lier le bouton de fermeture à une entrée qui, lorsqu'elle est active, masque à nouveau la liste.

body{
  padding: 20px;
}

a, label{
  text-decoration: none;
  cursor: pointer;
  color: Lime;
  font-weight: bold;
}

.container{
  border: 1px solid Lime;
  padding: 10px;
  width: 200px;
}

.dropdown{
  display: none;
  border: 1px solid orange;
  background: green;
  margin-top: 10px;
  padding: 10px;
}

#close, #close:active + .dropdown{
  display: none;
}

.container:hover .dropdown{
  display: block;
}

.dropdown > ul{
  padding: 0;
  list-style: none;
}
<div class="container">
  Drop down menu
  <button id="close"></button>
  <div class="dropdown">
    <label for="close">X Close</label>
    <ul>
      <li class="link"><a href="http://www.google.com">Go to link 1</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
      <li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    </ul>
  </div>
</div>

Le input avec id="close" est inséré avant la liste et sera déclenché par l'étiquette avec for="close"
Une fois déclenchée, la règle suivante prendra effet:

#close, #close:active + .dropdown{
  display: none;
}

Ce qui cache la liste.
Mais lorsque vous survolez le .container, il réapparaîtra, ce qui vous permettra de répéter le processus . Il n’est pas nécessaire d’avoir du JavaScript inutile ici. Une entrée fera l'affaire.

Il y avait aussi des problèmes avec votre code. Vous aviez le texte Drop down menu et CLOSE THIS CONTENT directement dans un ul, ce qui ne peut pas être fait. Un ul ne peut contenir que des li et rien d'autre.

J'espère que cela t'aides

0
Gust van de Wal

Je suggérerais d'essayer d'utiliser jQuery pour gérer la fermeture du conteneur uniquement lorsqu'un lien est activé. pointer-events ont de nombreux problèmes. Pour cette raison, ils ont décidé de reporter la fonctionnalité sur CSS4.

Je pense aussi que pointer-events: none; empêche le déclenchement d’événements de clic. Par conséquent, utiliser jQuery uniquement pour le lien ne fonctionnera pas. Je pense que vous devrez corriger l'ouverture et la fermeture du conteneur avec jQuery.

0
Kevinvhengst

Une des options est d'utiliser animate. J'ai donné un exemple avec votre code avec opacity. Utiliser visibility:hidden ou overflow:hidden améliorera votre code.

    body {
        padding: 20px;
    }
    .container {
        border: 1px solid Lime;
        padding: 10px;
        width: 200px;
    }
    .test1 {
        display: none;
        border: 1px dashed orange;
        background: green;
        padding: 10px;
        pointer-events: none;
    }
    .container:hover .test1 {
        display: inline-block;
    }
    
    a {
        pointer-events: auto;
        color: Lime;
        font-weight: bold;
    }


.container .test1 {
  -webkit-animation: seconds 1.0s forwards;
  -webkit-animation-iteration-count: 1;
  -webkit-animation-delay: 2s;
  animation: seconds 1.0s forwards;
  animation-iteration-count: 1;
  animation-delay: 2s;
  position: relative;
}
@-webkit-keyframes seconds {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;

  }

@keyframes seconds {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;

  }
}
    <ul class="container">
    	 Drop down menu
    	<li class="test1">
    	<a class="dropdown" href="#">X Close</a>
    	<ul class="content">
    		 CLOSE THIS CONTENT
    		<li class="link"><a href="http://www.google.com">Go to link 1</a></li>
    		<li class="link"><a href="https://www.google.co.uk">Go to link 2</a></li>
    		<li class="link"><a href="https://www.google.co.uk">Go to link 3</a></li>
    	</ul>
0
shubham agrawal
.container:hover .test1:active {
display: none;
}

Changer cela comme à

.container:hover .test1:focus{
    display: none;
    }

Ce qui se passe ici, c’est que lorsque votre div obtient le code "actif" de psuedo de votre lien de clic, il se cache avant que les bulles du DOM ne se retrouvent dans votre lien pour vous permettre de rediriger la redirection. Le changer en focus pourrait permettre au clic de passer réellement?

0
jjeining

Pourquoi avez-vous ajouté "pointer-events: none;" à l'élément de liste .test1? Ceci écrase votre pointer-events: auto;. Essayez de le supprimer, car il lie votre événement click.

0
ReAlPeNx