Jump to content
ike

Dropdown menu not working with sticky navbar

Recommended Posts

I'm trying to use the responsive navbar and sticky code but the dropdown will not show when the sticky kicks in.  I tried removing the overflow: hidden; on the .dropdown but that didn't help.  Also I can't get the responsive menu to work, seems like there is a conflict with the two different scripts.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>stickydropdown.html</title>

<style>

body {
 margin:0;
 font-family:Arial
}

.header{
 width: 100%;
 height: 125px;
 background-color: #999;
}


.body-content{
 width: 100%;
 min-height: 1025px;
 background-color: #fff;
}


.footer{
 width: 100%;
 height: 175px;
 background-color: #000;
}

.topnav {
  background-color: #333;
  overflow: hidden;
}

.topnav a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
}

.active {
  background-color: ;
  color: white;
}

.topnav .icon {
  display: none;
}

.dropdown {
    float: left;
 overflow: ;
}

.dropdown .dropbtn {
    font-size: 17px;   
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: #333;
    font-family: inherit;
    margin: 0;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-content a {
    float: none;
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
}

.topnav a:hover, .dropdown:hover .dropbtn {
  background-color: #555;
  color: white;
}

.dropdown-content a:hover {
    background-color: #ddd;
    color: black;
}

.dropdown:hover .dropdown-content {
    display: block;
}


/* Page content */
.content {
  padding: 16px;
}

/* The sticky class is added to the navbar with JS when it reaches its scroll position */
.sticky {
  position: fixed;
  top: 0;
  width: 100%;
}

/* Add some top padding to the page content to prevent sudden quick movement (as the navigation bar gets a new position at the top of the page (position:fixed and top:0) */
.sticky + .content {
  padding-top: 60px;
}

@media screen and (max-width: 600px) {
  .topnav a:not(:first-child), .dropdown .dropbtn {
    display: none;
  }
  .topnav a.icon {
    float: right;
    display: block;
  }
}

@media screen and (max-width: 600px) {
  .topnav.responsive {position: relative;}
  .topnav.responsive .icon {
    position: absolute;
    right: 0;
    top: 0;
  }
  .topnav.responsive a {
    float: none;
    display: block;
    text-align: left;
  }
  .topnav.responsive .dropdown {float: none;}
  .topnav.responsive .dropdown-content {position: relative;}
  .topnav.responsive .dropdown .dropbtn {
    display: block;
    width: 100%;
    text-align: left;
  }
}
</style>
</head>
<body>


<div class="header"></div>

 

<div class="topnav" id="myTopnav">
  <a href="stickydropdown.html" class="active">Home</a>
 
  <div class="dropdown">
    <button class="dropbtn">Products
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="plinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
 
  <div class="dropdown">
    <button class="dropbtn">Services
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="slinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
 
 <a href="a.html">About</a>
  <a href="news.html">News</a>
  <a href="c.html">Contact</a>
  <a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>

<div class="body-content">
<div style="padding-left:16px">
  <h2>Home</h2>
  <p>Resize the browser window to see how it works.</p>
  <p>Hover over the dropdown button to open the dropdown menu.</p>
</div>
</div>


<div class="footer"></div>


<script>
function myFunction() {
    var x = document.getElementById("myTopnav");
    if (x.className === "topnav") {
        x.className += " responsive";
    } else {
        x.className = "topnav";
    }
}
</script>


<script>
// When the user scrolls the page, execute myFunction
window.onscroll =  function() {myFunction()};

// Get the topnav
var topnav = document.getElementById("myTopnav");

// Get the offset position of the navbar
var sticky = topnav.offsetTop;
 
// Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunction() {
   if (window.pageYOffset >= sticky) {
    topnav.classList.add("sticky")
   } else {
   topnav.classList.remove("sticky");
  }
 }
</script>

</body>
</html>

 

Share this post


Link to post
Share on other sites

You can't have two identical function names, it will only act on one, change sticky function name call on window scroll event and make sure the sticky function name matches.

window.onscroll =  function() {myFunctionSticky()}; 
function myFunctionSticky() {
   if (window.pageYOffset >= sticky) {
    topnav.classList.add("sticky")
   } else {
   topnav.classList.remove("sticky");
  }
 }

 

Edited by dsonesuk

Share this post


Link to post
Share on other sites

Thanks for the replay.  I made the suggested changes and it kind of works.  If reduce the page width and scroll all the way to the bottom the navbar moves to the top of the page however, when I click the menu icon, the menu disappears or jumps out of view now.  If I reduce the width but do not scroll all the way to the bottom of the page and click on the menu icon the dropdown works.

Share this post


Link to post
Share on other sites

Ahh that's because one function removes all classes with 'topnav' remaining, removing the 'sticky' class. Also you require to override the '.topnav.responsive' class style of position relative, if 'sticky' class present, to remain position: fixed;

try

 <!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>stickydropdown.html</title>

<style>

body {
 margin:0;
 font-family:Arial
}

.header{
 width: 100%;
 height: 125px;
 background-color: #999;
}


.body-content{
 width: 100%;
 min-height: 1025px;
 background-color: #fff;
}


.footer{
 width: 100%;
 height: 175px;
 background-color: #000;
}

.topnav {
  background-color: #333;
  overflow: hidden;
}

.topnav a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
}

.active {
  background-color: ;
  color: white;
}

.topnav .icon {
  display: none;
}

.dropdown {
    float: left;
 overflow: ;
}

.dropdown .dropbtn {
    font-size: 17px;   
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: #333;
    font-family: inherit;
    margin: 0;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-content a {
    float: none;
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
}

.topnav a:hover, .dropdown:hover .dropbtn {
  background-color: #555;
  color: white;
}

.dropdown-content a:hover {
    background-color: #ddd;
    color: black;
}

.dropdown:hover .dropdown-content {
    display: block;
}


/* Page content */
.content {
  padding: 16px;
}

/* The sticky class is added to the navbar with JS when it reaches its scroll position */
.sticky,.topnav.responsive.sticky {

  position: fixed;
  top: 0;
  width: 100%;
}

/* Add some top padding to the page content to prevent sudden quick movement (as the navigation bar gets a new position at the top of the page (position:fixed and top:0) */
.sticky + .content {
  padding-top: 60px;
}

@media screen and (max-width: 600px) {
  .topnav a:not(:first-child), .dropdown .dropbtn {
    display: none;
  }
  .topnav a.icon {
    float: right;
    display: block;
  }
}

@media screen and (max-width: 600px) {
  .topnav.responsive {position: relative;}
  .topnav.responsive .icon {
    position: absolute;
    right: 0;
    top: 0;
  }
  .topnav.responsive a {
    float: none;
    display: block;
    text-align: left;
  }
  .topnav.responsive .dropdown {float: none;}
  .topnav.responsive .dropdown-content {position: relative;}
  .topnav.responsive .dropdown .dropbtn {
    display: block;
    width: 100%;
    text-align: left;
  }
}
</style>
</head>
<body>


<div class="header"></div>

 

<div class="topnav" id="myTopnav">
  <a href="stickydropdown.html" class="active">Home</a>
 
  <div class="dropdown">
    <button class="dropbtn">Products
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="plinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
 
  <div class="dropdown">
    <button class="dropbtn">Services
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="slinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
 
 <a href="a.html">About</a>
  <a href="news.html">News</a>
  <a href="c.html">Contact</a>
  <a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>

<div class="body-content">
<div style="padding-left:16px">
  <h2>Home</h2>
  <p>Resize the browser window to see how it works.</p>
  <p>Hover over the dropdown button to open the dropdown menu.</p>
</div>
</div>


<div class="footer"></div>


<script>
function myFunction() {
    var x = document.getElementById("myTopnav");
 
    if (!x.classList.contains("responsive")) {
        x.classList.add("responsive");
    } else {
    
        x.classList.remove("responsive");
    }
}
</script>


<script>
// When the user scrolls the page, execute myFunction
window.onscroll =  function() {myFunctionSticky()}; 

// Get the topnav
var topnav = document.getElementById("myTopnav");

// Get the offset position of the navbar
var sticky = topnav.offsetTop;
 
// Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunctionSticky() {
   if (window.pageYOffset >= sticky) {
    topnav.classList.add("sticky")
   } else {
   topnav.classList.remove("sticky");
  }
 }
</script>

</body>
</html> 

 

Edited by dsonesuk

Share this post


Link to post
Share on other sites

Thanks a bunch.  I understand this change,

/* The sticky class is added to the navbar with JS when it reaches its scroll position */

.sticky,.topnav.responsive.sticky {

 

  position: fixed;

  top: 0;

  width: 100%;

}

 

but would never have figured out the changes you made to the first script.

The dropdowns still will not work once the navbar gets stuck unless you reduce the screen size so the responsive kicks in.  I thought it was the overflow: hidden; on the .dropdown but I removed that and it still does not work.  Any suggestions on that?

Thanks again for all your help!

Share this post


Link to post
Share on other sites

Remove overflow: hidden; as you have done and add

.topnav::after {
    clear: both;
    content: "";
    display: block;
}

A block element container, with floated child elements such as the anchors and div's is not able to detect the area they occupy so the height becomes 0, overflow: hidden is used to fixed this, that becomes a problem when used with a menu, BUT! using content:""; this will add a sort of textual block element which has clear: both, 0 height running below the menu elements that the container CAN detect, so it envelopes the menu again as it did with overflow: hidden.

Edited by dsonesuk

Share this post


Link to post
Share on other sites

I finally got it working by giving the .topnav a fixed height and removing the overflow: hidden;. 

.topnav {
background-color: #333;
overflow: ;

height: 48px;
}

However, now if you reduce the screen size when you click the menu icon the bottom three menu items do not have the dark background color.

Share this post


Link to post
Share on other sites

Your suggestion has things working properly now. Thank you very much!

I hope I can understand things better someday, as the smallest changes can make such a dramatic impact.

Forgot we are going to need a sub menu on one of the dropdowns. Any chance of creating a sub menu with in the current dropdown menu?  Seems like I might have to switch to a different menu type using unordered list & li's to accomplish this which will probably blow everything apart.

 

Share this post


Link to post
Share on other sites

That's not removing! that's  a possible breaking the css and likely to affect css following it! Remove it completely, comment it out completely never leave it half done.

The container envelopes all the menus to give them a background colour, by restricting the height, it no longer adjusts in height envelope anymore, the menu items and text are there, they just have contrasting background to show them anymore.

Share this post


Link to post
Share on other sites

I created a sub menu on one of my dropdowns which seems to be working.  However,  i'm struggling on how the get the Sub Menu Text aligned to the left.  Currently it's centered and I'd like it to line up with the other links. Also, is there a way to have an arrow pointing to the right on the Sub Menu?

 

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

<title></title>

<style>

body {
 margin:0;
 font-family: Arial;
}

.header{
 width: 100%;
 height: 125px;
 background-color: #999;
}


.body-content{
 width: 100%;
 min-height: 1025px;
 background-color: #fff;
}


.footer{
 width: 100%;
 height: 175px;
 background-color: #000;
}

.topnav {
  background-color: #333;
  overflow: ;
 
}

.topnav::after {
    clear: both;
    content: "";
    display: block;
}

.topnav a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
}

.active {
  background-color: ;
  color: white;
}

.topnav .icon {
  display: none;
}

.dropdown {
    float: left;
    overflow: ;
}

.dropdown .dropbtn {
    font-size: 17px;  
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: #333;
    font-family: inherit;
    margin: 0;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-content a {
    float: none;
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
}

 

 

.subdropdown .subdropbtn {
    font-size: 17px;  
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: #555 ;
    font-family: inherit;
    width: 160px;
}

 

.subdropdown-content {
    display: none;
    position: absolute;
    height: 0px;
 background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.subdropdown-content a {
    float: none;
    color: black;
    padding: 14px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
 position: relative;
    top: -48px;
    left: 160px;
 background-color: #f9f9f9;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}


.topnav a:hover, .dropdown:hover .dropbtn {
  background-color: #555;
  color: white;
}

.dropdown-content a:hover {
    background-color: #ddd;
    color: black;
}

.subdropdown-content a:hover {
    background-color: #ddd;
    color: black;
}

.dropdown:hover .dropdown-content {
    display: block;
}

.subdropdown:hover .subdropdown-content {
    display: block;
}

/* Page content */
.content {
  padding: 16px;
}

 

/* The sticky class is added to the navbar with JS when it reaches its scroll position */
.sticky,.topnav.responsive.sticky {

  position: fixed;
  top: 0;
  width: 100%;
}

/* Add some top padding to the page content to prevent sudden quick movement (as the navigation bar gets a new position at the top of the page (position:fixed and top:0) */
.sticky + .content {
  padding-top: 60px;
}

@media screen and (max-width: 600px) {
  .topnav a:not(:first-child), .dropdown .dropbtn {
    display: none;
  }
  .topnav a.icon {
    float: right;
    display: block;
  }
}

@media screen and (max-width: 600px) {
  .topnav.responsive {position: relative;}
  .topnav.responsive .icon {
    position: absolute;
    right: 0;
    top: 0;
  }
  .topnav.responsive a {
    float: none;
    display: block;
    text-align: left;
  }
  .topnav.responsive .dropdown {float: none;}
  .topnav.responsive .dropdown-content {position: relative;}
  .topnav.responsive .dropdown .dropbtn {
    display: block;
    width: 100%;
    text-align: left;
  }
}
</style>
</head>
<body>


<div class="header"></div>

 

<div class="topnav" id="myTopnav">
  <a href="home2.html" class="active">Home</a>
  <a href="a2.html">About</a>
 
  <div class="dropdown">
    <button class="dropbtn">Products
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="plone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
 
  <div class="dropdown">
    <button class="dropbtn">Services
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="slone.html">Link 1</a>
      <a href="#">Link 2</a>
 
  <div class="subdropdown">
    <button class="subdropbtn">Sub Menu
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="subdropdown-content">
      <a href="smlone.html">Sub Menu Link 1</a>
      <a href="#">Sub Menu Link 2</a>
      <a href="#">Sub Menu Link 3</a>
    </div>
  </div>

 </div>
</div>
 
  <a href="news2.html">News</a>
  <a href="c2.html">Contact</a>
  <a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>

<div class="body-content">
<div style="padding-left:16px">
  <h2>Home</h2>
  <p>Resize the browser window to see how it works.</p>
  <p>Hover over the dropdown button to open the dropdown menu.</p>
</div>
</div>


<div class="footer"></div>


<script>
function myFunction() {
    var x = document.getElementById("myTopnav");
 
    if (!x.classList.contains("responsive")) {
        x.classList.add("responsive");
    } else {
   
        x.classList.remove("responsive");
    }
}
</script>


<script>
// When the user scrolls the page, execute myFunction
window.onscroll =  function() {myFunctionSticky()};

// Get the topnav
var topnav = document.getElementById("myTopnav");

// Get the offset position of the navbar
var sticky = topnav.offsetTop;
 
// Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunctionSticky() {
   if (window.pageYOffset >= sticky) {
    topnav.classList.add("sticky")
   } else {
   topnav.classList.remove("sticky");
  }
 }
</script>

</body>
</html>

 

 

Share this post


Link to post
Share on other sites

Just add  text-align:left  under  .subdropdown .subdropbtn

As for the arrow, in the HTML change the  <i class="fa fa-caret-down"></i> to <i class="fa fa-caret-right"></i>

Share this post


Link to post
Share on other sites

I could have sworn I tried that but must have mucked it up somehow as it working now along with the right arrow. Many thanks!

I see most navigation menus are made up of unordered lists and list items.  Are there benefits of creating it that way opposed to the div structure I used? 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×