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

RulerNature picture RulerNature · Dec 9, 2016 · Viewed 18.1k times · Source

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.

Answer

kukkuz picture kukkuz · Dec 14, 2016

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>