Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show dropdown-menu on hover and close on click using only CSS

Can someone help me with an explanation as to why the links from a dropdown menu are not working when I click on them? Maybe because of pointer events? I'm trying to have a dropdown menu that is closing after a link is clicked or the close button is clicked. I have added some cool stuff like hiding parent container when a link is clicked.

There are many options doing that:

  1. using :focus but when the focus is used the drop-down will not be triggered on the next hover over dropdown.

  2. using :active on container and pointer-events to point only the active links, but pointer events is buggy

  3. using :target but has the same problem as :focus, will not trigger the second hoover.

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>
like image 646
RulerNature Avatar asked Dec 09 '16 14:12

RulerNature


3 Answers

Quick Check : Working JSFiddle

Can someone help me with an explanation as to why the links from a dropdown menu are not working when I click on them? Maybe because of pointer events?

Explanation on why this behavior: Yes you are right, It is because of the way you are using the :active selector logic, To explain in detail, consider your this CSS rule

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

You have your menu links under your main li.test1 and any click on the inner links are also bubbled up to this element, so its as good as clicking the li. So as soon as the mouse is held down (mouse down event) it triggers the :active event and you are hiding the links (ie: li.test1), But a click event is complete only when mouse is both down and up. So by now the li is hidden and the mouse up is no longer on the link. So as you see there is no chance of the click event to be triggered. This is the issue.


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: Rather than wrapping up your inner menu links inside the li.test1 you can work with two different li , One for the X CLose and other for holding the menu links. With this in place we can make sure when ever the li.test1 is active (ie mouse is down) we can hide it and also the other new li which is adjacent to it. So this means when ever the user clicks on the X Close li we hide the menu, If he clicks on the other menu items you are redirected.

So the changes in your HTML structure should be like

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

And Main CSS rule is

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

Below is a SO working Snippet

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: The blank screen when you click on the links are due to the google's security Restrictions on cross origin policy which gives this error in 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'.

However you can see the requests in the network tab when you click on the links.

Hope this helps!!

like image 194
Rajshekar Reddy Avatar answered Nov 17 '22 23:11

Rajshekar Reddy


I would do this normally using JS - but with CSS there is a hack:

First create an input with id close and a label for this that wraps our close button:

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

and add in this style instead of the current .test1:active:

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

See demo below:

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>

But the above code has an invalid input element inside a ul - to prevent that you can edit the markup a bit to create one more wrapper for the ul (maybe you have to adjust the widths/padding a bit due to the markup change) - see code below:

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>
like image 4
kukkuz Avatar answered Nov 18 '22 00:11

kukkuz


It doesn't seem to work because on mouse down the :hover-class for keeping the dropdown menu open is vanished. So the mouse up event is not executed on the link because the dropdown is already closed again, so no click is performed. You should use javascript to open and close the dropdown menu.

like image 1
Martin Cup Avatar answered Nov 18 '22 00:11

Martin Cup