Hamburger menu on Sticky scroll only

  • Hi,
    Our current header configuration is the following:

    Dekstop: Header Element with Container position set to Sticky.
    Mobile: Customizer > Layout > Mobile Header: ON

    What we would like to achieve is when you start to scroll on DESKTOP the menu changes from a normal full-width navigation to a hambuger menu, is this possible?

  • To implement this, you’ll need two things:

    1. Hook Element (wp_footer, Display Rules -> Entire Site)

    <script>
    (function () {
      var gbHeader = document.querySelector('.gb-element-8cfaddfb');
      var mobileHeader = document.getElementById('mobile-header');
      if (!gbHeader || !mobileHeader) return;
    
      function onScroll() {
        if (window.scrollY > 80) {
          gbHeader.style.display = 'none';
          mobileHeader.classList.add('desktop-scrolled');
        } else {
          gbHeader.style.display = '';
          mobileHeader.classList.remove('desktop-scrolled');
        }
      }
    
      window.addEventListener('scroll', onScroll, { passive: true });
    })();
    </script>

    2. Customizer → Additional CSS

    @media (min-width: 1025px) {
      #mobile-header.desktop-scrolled {
        display: flex !important;
        position: fixed;
        top: 32px;
        left: 0;
        right: 0;
        z-index: 9999;
        background-color: var(--contrast);
      }
      #mobile-header.desktop-scrolled .site-logo {
        position: static !important;
        left: auto !important;
        margin-left: 0 !important;
      }
      #mobile-header.desktop-scrolled #mobile-menu {
        display: none !important;
      }
      #mobile-header.desktop-scrolled .menu-toggle {
        display: none !important;
      }
      #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle {
        display: flex !important;
      }
      #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle svg {
        width: 1.6em !important;
        height: 1.6em !important;
      }
    }

    The top: 32px accounts for the WP admin bar — if this is going live for logged-out visitors you can change that to top: 0.

    One note: the class gb-element-8cfaddfb is auto-generated by GB. If it ever changes (e.g. after a block reset), the JS will stop working. To future-proof it, I’d recommend adding a custom CSS class to that GB container in the editor and updating the selector to match.

  • Thanks so much for this, its mostly working well. There is a slight flicker when it transitions from the full-width nav to the hamburger nav, anything we can do to prevent that?. Also ideally want the hamburger icon at the end of the header and the close icon to be in the same location as it.

  • Hello,

    Also ideally want the hamburger icon at the end of the header and the close icon to be in the same location as it.

    Do you mean that you want the close icon to be next to the logo like the open icon is? That would also affect the mobile functionality, though.

  • Not quite, we’d want it like this: https://snipboard.io/PgACYt.jpg
    So the hamburger is at the end of the navbar and the close icon would be in the same position when the menu is opened.

  • Here’s everything you need to implement this.

    Hook element

    <script>
    (function () {
      var gbHeader = document.querySelector('.custom-header');
      var mobileHeader = document.getElementById('mobile-header');
      var insideNav = document.querySelector('#mobile-header .inside-navigation');
      var logo = document.querySelector('#mobile-header .site-logo');
      var menuBarItems = document.querySelector('#mobile-header .menu-bar-items');
      if (!gbHeader || !mobileHeader || !insideNav || !logo || !menuBarItems) return;
    
      var spacer = document.createElement('div');
      spacer.className = 'desktop-scrolled-spacer';
    
      function onScroll() {
        if (window.scrollY > 80) {
          gbHeader.style.visibility = 'hidden';
          gbHeader.style.opacity = '0';
          mobileHeader.classList.add('desktop-scrolled');
          insideNav.style.width = '100%';
          insideNav.style.maxWidth = '100%';
          insideNav.style.justifyContent = 'center';
          if (!document.querySelector('.desktop-scrolled-spacer')) {
            insideNav.insertBefore(spacer, logo);
          }
          logo.style.flex = '0 0 auto';
          menuBarItems.style.flex = '1';
          menuBarItems.style.justifyContent = 'flex-end';
          menuBarItems.style.display = 'flex';
        } else {
          gbHeader.style.visibility = '';
          gbHeader.style.opacity = '';
          mobileHeader.classList.remove('desktop-scrolled');
          insideNav.style.width = '';
          insideNav.style.maxWidth = '';
          insideNav.style.justifyContent = '';
          if (spacer.parentNode) spacer.parentNode.removeChild(spacer);
          logo.style.flex = '';
          menuBarItems.style.flex = '';
          menuBarItems.style.justifyContent = '';
          menuBarItems.style.display = '';
        }
      }
    
      window.addEventListener('scroll', onScroll, { passive: true });
    })();
    </script>

    Customizer → Additional CSS

    .custom-header {
      transition: opacity 200ms ease, visibility 200ms ease;
    }
    
    .desktop-scrolled-spacer {
      flex: 1;
    }
    
    #mobile-header.desktop-scrolled #mobile-menu {
      display: none !important;
    }
    
    #mobile-header.desktop-scrolled .menu-toggle {
      display: none !important;
    }
    
    #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle {
      display: flex !important;
    }
    
    #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle svg {
      width: 1.6em !important;
      height: 1.6em !important;
    }
    
    #generate-slideout-menu .slideout-exit {
      position: fixed !important;
      right: 30px !important;
      top: 32px !important;
    }
  • Added the code but now the header completely disappears on scroll on desktop.

  • The GB header is being hidden but the #mobile-header isn’t showing because on desktop it’s set to display: none by GP’s mobile header CSS. We need to explicitly show it when scrolled. Add this to the CSS in the Hook Element:

    <script>
    (function () {
    var gbHeader = document.querySelector(‘.custom-header’);
    var mobileHeader = document.getElementById(‘mobile-header’);
    var insideNav = document.querySelector(‘#mobile-header .inside-navigation’);
    var logo = document.querySelector(‘#mobile-header .site-logo’);
    var menuBarItems = document.querySelector(‘#mobile-header .menu-bar-items’);
    if (!gbHeader || !mobileHeader || !insideNav || !logo || !menuBarItems) return;

    var style = document.createElement(‘style’);
    style.textContent = `
    .custom-header {
    transition: opacity 200ms ease, visibility 200ms ease;
    }
    .desktop-scrolled-spacer {
    flex: 1;
    }
    @media (min-width: 1025px) {
    #mobile-header.desktop-scrolled {
    display: flex !important;
    }
    #mobile-header.desktop-scrolled #mobile-menu {
    display: none !important;
    }
    #mobile-header.desktop-scrolled .menu-toggle {
    display: none !important;
    }
    #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle {
    display: flex !important;
    }
    #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle svg {
    width: 1.6em !important;
    height: 1.6em !important;
    }
    #generate-slideout-menu .slideout-exit {
    position: fixed !important;
    right: 30px !important;
    top: 32px !important;
    }
    }
    `;
    document.head.appendChild(style);

    var spacer = document.createElement(‘div’);
    spacer.className = ‘desktop-scrolled-spacer’;

    function onScroll() {
    if (window.scrollY > 80) {
    gbHeader.style.visibility = ‘hidden’;
    gbHeader.style.opacity = ‘0’;
    mobileHeader.classList.add(‘desktop-scrolled’);
    insideNav.style.width = ‘100%’;
    insideNav.style.maxWidth = ‘100%’;
    insideNav.style.justifyContent = ‘center’;
    if (!document.querySelector(‘.desktop-scrolled-spacer’)) {
    insideNav.insertBefore(spacer, logo);
    }
    logo.style.flex = ‘0 0 auto’;
    menuBarItems.style.flex = ‘1’;
    menuBarItems.style.justifyContent = ‘flex-end’;
    menuBarItems.style.display = ‘flex’;
    } else {
    gbHeader.style.visibility = ”;
    gbHeader.style.opacity = ”;
    mobileHeader.classList.remove(‘desktop-scrolled’);
    insideNav.style.width = ”;
    insideNav.style.maxWidth = ”;
    insideNav.style.justifyContent = ”;
    if (spacer.parentNode) spacer.parentNode.removeChild(spacer);
    logo.style.flex = ”;
    menuBarItems.style.flex = ”;
    menuBarItems.style.justifyContent = ”;
    menuBarItems.style.display = ”;
    }
    }

    window.addEventListener(‘scroll’, onScroll, { passive: true });
    })();
    </script>

    The key addition is #mobile-header.desktop-scrolled { display: flex !important; } wrapped in the @media (min-width: 1025px) query — so it only kicks in on desktop and doesn’t interfere with the mobile header behaviour.

    Please replace your Additional CSS with this updated version:

    .custom-header {
      transition: opacity 200ms ease, visibility 200ms ease;
    }
    
    .desktop-scrolled-spacer {
      flex: 1;
    }
    
    @media (min-width: 1025px) {
      #mobile-header.desktop-scrolled {
        display: flex !important;
      }
      #mobile-header.desktop-scrolled #mobile-menu {
        display: none !important;
      }
      #mobile-header.desktop-scrolled .menu-toggle {
        display: none !important;
      }
      #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle {
        display: flex !important;
      }
      #mobile-header.desktop-scrolled .menu-bar-item.slideout-toggle svg {
        width: 1.6em !important;
        height: 1.6em !important;
      }
      #generate-slideout-menu .slideout-exit {
        position: fixed !important;
        right: 30px !important;
        top: 32px !important;
      }
    }

    The only changes are wrapping the #mobile-header.desktop-scrolled rules inside @media (min-width: 1025px) and adding #mobile-header.desktop-scrolled { display: flex !important; } to ensure the header is visible on desktop when scrolled.

  • Thank you its almost perfect now. Only slight niggle is on both the desktop sticky navbar and on mobile when you open the hamburger menu the logo shifts either up slightly or over to the right.
    Would be nice for it to stay in the same position as when the menu is closed.

    Also just noticed when testing on an actual mobile device (not mobile on desktop) when you scroll down only the bottom half of the sticky navbar is visible.

  • Maybe add this CSS:

    .off-canvas-logo,
    button.slideout-exit {
        padding-top: 37px;
    }
    
    @media (max-width: 1024px) {
        .off-canvas-logo {
            padding-top: 46px;
            padding-right: 65px;
        }
    }
  • Thanks, tweaked the padding-top values and it seems good now. However, on mobile, only the bottom half of the sticky navbar is visible when you scroll down, oddly when you scroll back up its fully visible.

  • Hi,

    on mobile, only the bottom half the sticky navbar is visible when you scroll down, oddly when you scroll back up its fully visible.

    Hmmm, not sure what you mean here, can you send a screenshot of the issue?

  • Sure see screenshot: https://prnt.sc/Ku1u11OE5f6Y

    On a mobile device when you scroll down the sticky navbar is partially obscured.

  • Strangely I can’t recreate this issue now.

  • Hi there,

    On a mobile device when you scroll down the sticky navbar is partially obscured.

    I’m not seeing the issue either. It was probably just a caching issue earlier.

    Let us know if it happens again so we can take another look.

  • My colleagues are still experiencing issues on mobile, see screenshot: https://prnt.sc/XpdwgQTsxTPN

    Heres their description of the issue: ‘On my actual mobile, the sticky menu isn’t there but it is when you scroll up, but it is sort of broken – the logo is on the left, slightly off screen, the burger off screen on the right.’

    Any further help appreciated.

Viewing 16 posts - 1 through 16 (of 23 total)
  • You must be logged in to reply to this topic.