Search code examples
javascriptcssexpresshandlebars.js

Toggle button takes two clicks


I have made a toggle button to show some navlinks on mobile screens. However on the first page load it takes two clicks. After that point it toggle perfectly fine. How can I make it so it functions correctly first time?

Heres the script that contains the function.

script.js

function ToggleNavLinks() { /
    var navLink = document.getElementsByClassName("nav-links")[0]; 
    
    if (navLink.style.display === "none") { 
        navLink.style.display = "flex"; 
    } 
    else {
        navLink.style.display = "none"; 
    }
}

Heres the layout file that contains the front-end element. I have tested if it was the external script reference and it definitely works.

layout.hbs


<!DOCTYPE html>
<html lang="en">
    <head>   

        <title>{{title}}</title>        

        <meta charset="utf-8"/> <!-- Charset -->
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <link rel='stylesheet' href='/stylesheets/style.css'/> 
        <script type="text/javascript" src="/javascripts/script.js"></script>

    </head>

    <body>
        <header>
            <nav class="navbar"> 
                <img class="logo" alt="logo" src="images/logo-stock.png">

                
                <a class="nav-toggle" onclick="ToggleNavLinks()" > 
                    <span class="bar"></span> 
                    <span class="bar"></span> 
                    <span class="bar"></span> 
                </a>

                <!-- Links used in the navbar -->
                <div class="nav-links"> 
                    <ul>
                        <li> 
                            <a href="#">Home</a> 
                        </li>
                        <li> 
                            <a href="#">Projects</a> 
                        </li>
                        <li> 
                            <a href="#">Contact</a>
                        </li>
                    </ul>
                </div>
            </nav>
        </header>
        
        <div>
            {{{body}}} 
        </div>
    </body>
</html>

Ill also include the stylesheet in case that has anything to do with it.

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap'); 

:root { 
  font-size: 16px; 
  font-family: 'Roboto', sans-serif; 
  --text-primary: white; 
  --text-secondary: #4c6bc1; 
  --bg-primary: #101316; 
  --bg-secondary: #181a1d; 
}

* {
  box-sizing: border-box; 
}

body { 
  background-color: var(--bg-primary);
  margin: 0; 
  padding: 0; 
}

body::-webkit-scrollbar {
  width: 0.25rem;
}

body::-webkit-scrollbar-track { 
  background: #181a1d; 
}

body::-webkit-scrollbar-thumb { 
  background: #4c6bc1; 
}

.navbar {
  justify-content: space-between; 
  position: relative; 
  background-color: var(--bg-secondary); 
  display: flex; 
  justify-content: space-between; 
  align-items: center; 
}

.navbar img { 
  width: 250px; 
  height: 100px; 
}

.logo{ 
  max-width: 100%; 
  height: auto; 
}

.navbar-links { 
  height: 100%;
}

.nav-links ul { 
  margin: 0;
  padding: 0; 
  display: flex; 
}

.nav-links li { 
  list-style: none; 
}

.nav-links li a { 
  font-size: 1.5rem;
  text-decoration: none; 
  color: white;
  padding: 1rem; 
  display: block; 
}

.nav-links li a:hover { 
  color: #4c6bc1; 
}

.nav-toggle { 
  position: absolute;
  top: 1.5rem; 
  right: 1rem; 
  display: none; 
  flex-direction: column; 
  justify-content: space-between; 
  height: 21px; 
  width: 30px; 
}

.nav-toggle:hover { 
  cursor: pointer; 
}

.nav-toggle .bar { 
  height: 3px; 
  width: 100%; 
  background-color: white; 
  border-radius: 10px;
}

@media (max-width: 800px) {
  .nav-toggle { 
    display: flex;
  }

  .nav-links { 
    display: none;
    width: 100%; 
  }

  .navbar { 
    flex-direction: column;
    align-items: flex-start;
  }

  .nav-links ul { 
    width: 100%;
    flex-direction: column;
  }

  .nav-links li {
    text-align: center;
  }

  .nav-links.active { 
    display: flex;
}

Solution

  • element.style.display === 'none'
    

    is true when the element has an inline style attribute, which includes display: none. Note that this is true regardless of the actual computed style property of the element. You can check it in this example:

    console.log(document.querySelector('.test').style.display);
    .test {
      display: block !important;
    }
    code {
      background-color: #eee;
    }
    <div style="display: none;" class="test">I haz <code>style.display === 'none'</code>. You are looking at me. Stop staring, it's not nice.</div>

    To check the computed property of the display, use

    window.getComputedStyle(element).display === 'none'
    

    In conclusion, replace

    if (navLink.style.display === "none") {
    

    with

    if (window.getComputedStyle(navLink).display === "none") {