JS dropdown menu best practice

Viewed 9780

I want to implement the following tiny drop down menu into my project.

Is there anything inherently wrong with my code? I attempted the :hover pseudo via CSS but was unsuccessful. Is there a better way to JS this thing?

document.querySelector('.dropbtn').addEventListener('mouseenter', function(){
  document.querySelector('.dropdown-content').style.visibility = 'visible'
})

document.querySelector('.dropbtn').addEventListener('mouseleave', function(){
  document.querySelector('.dropdown-content').style.visibility = 'hidden'
})
.dropdown {
  display: flex;
  align-items: flex-start;
}

.dropbtn {
    background-color: darkslategray;
    color: white;
    padding: 6px 10px 6px;
    font-size: 18px;
    border: none;
    cursor: pointer;
}

.dropdown-content {
  background-color: darkslategray;
  display: inline-grid;
  visibility: hidden;
  padding: 6px 10px 6px;
}

img {
  margin: 3px;
  height: 40px;
  width: 120px;
  border: 1px solid gray;
}
<div class="dropdown">
  <button class="dropbtn">Dropdown</button>
  <div class="dropdown-content">
    <img src="http://fullhdpictures.com/wp-content/uploads/2016/03/Blur-Backgrounds.jpg" alt="">
    <img src="http://akveo.com/blur-admin/assets/img/blur-bg-blurred.jpg" alt="">
    <img src="http://www.publicdomainpictures.net/pictures/50000/velka/blurred-background-green.jpg" alt="">
  </div>
</div>

Codepen: https://codepen.io/HelleFl/pen/KyWYYX

3 Answers

Although there are several posts describing how to create a dropdown menu using just HTML and CSS, I'll try to answer your question.

tl;dr: Use CSS over JS for better performance

CSS or JS? Which one is better?

Basically whenever possible, use CSS over JS. There is a great SO answer about this here.
Going further, CSS animations should be preferred over JS animations unless the animation should have some advanced effects. There is a good google developers blog post on this as well.

How to create a dropdown menu

You can find the answer here. Basically you need to set the :hover onto the parent element, that holds both the link and submenu.

li img {
  width: 120px;
  height: auto;
}

ul > li {
  display: inline;
  position: relative;
  min-width: 150px;
}

/* hide submenus by setting the max-height to 0 */
ul > li > ul {
  max-height: 0;
  overflow: hidden;
  transition: max-height .75s ease;
}

/* set max-height to an approximate height it could have */
ul > li:hover > ul {
  max-height: 300px;
}

ul.submenu {
  background: #eee;
  position: absolute;
  left: 0;
  top: 1em;
}

ul.submenu > li {
  display: block;
}
<nav>
  <ul>
    <li><a href="#">Hyperlink 1</a></li>
    <li>
      <a href="#">Hyperlink 2</a>
      <ul class="submenu">
        <li><img src="http://fullhdpictures.com/wp-content/uploads/2016/03/Blur-Backgrounds.jpg" alt=""></li>
        <li><img src="http://akveo.com/blur-admin/assets/img/blur-bg-blurred.jpg" alt=""></li>
        <li><img src="http://www.publicdomainpictures.net/pictures/50000/velka/blurred-background-green.jpg" alt=""></li>
      </ul>
    </li>
  </ul>
</nav>

I guess you was facing the same issue that I was facing when I checked your codepen, since the .dropbtn are in the same level as .dropdown-content, the selector .dropbtn:hover .dropdown-content wont work since its searching for a child inside .dropbtn, so you have to use the sibling selector:

.dropbtn:hover ~ .dropdown-content{
  visibility: visible
}

(CSS animation its better than Javascript)

Also, a good practice in Javascript is to save the DOM element into an variable if you will use it multiple times, so you dont have to search for the DOM element again:

var dropBtnDOM = document.querySelector('.dropbtn');
var dropdownContentDom = document.querySelector('.dropdown-content');
dropBtnDOM.addEventListener('mouseenter', function(){
    dropdownContentDom.style.visibility = 'visible'
})

dropBtnDOM.addEventListener('mouseleave', function(){
    dropdownContentDom.style.visibility = 'hidden'
})

.dropdown:hover .dropbtn ~ .dropdown-content{
  visibility: visible
}

Related