Scroll Animation, Elementor, GSAP

How to create a Shrinking Sticky Header in Elementor with GSAP

SHARE

Setup in Elementor

First we need to setup a wrapper Container, because GSAP cannot animate which have the position “fixed”. And we need the position “fixed” for our sticky header. 

Setup Wrapper Container: 

  • Full width, Width 100%, no gaps
  • HTML Tag: Header
  • No margin, no padding

Setup Sticky Header Container: 

  • Boxed or Full width, I used Boxed in the tutorial demo
  • (width 100% or boxed 1200px)
  • height: don’t enter any height value, otherwise the animation will stop working!
  • Direction: Row horizontal 
  • Justify Content: space between
  • Align Items: center
  • background: rgba(255, 255, 255, 0.2); (for glassmorphism effect, but you can enter any other color whether here or in the CSS Code as a starting color
  • Wrap: No wrap
  • Position: fixed
  • z-index: 9999
  • padding: top and bottom 0, left and right 20px
  • CSS Class: lux-header

Setup Logo Image: 

  • Width: clamp(3.75rem, 3.205vw + 3.029rem, 6.875rem)
  • Upload your Logo
  • CSS Class: lux-logo

Setup WordPress Menu: 

  • Desktop: 

    • Layout Horizontal
    • Full width
    • Change at Tablet Portrait
    • Text Align: Middle or Center
    • Toggle Align: right
    • Style Tab: Add Colors as wished
    • Advanced tab: set Width to Inline(auto) all devices
    • CSS-Class: lux-navigation

 

Setup Button: 

  • CSS Class: lux-button
  • Give it some Text like “Get started” or other Call to Action
  • Give it a background Color, border radius and border (if widhed) 

GSAP Code

Add this into your HTML widget

<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>

<script>
  gsap.registerPlugin(ScrollTrigger);

  // Define the elements
  const header = document.querySelector(".lux-header");
  const logo = document.querySelector(".lux-logo img");
  const button = document.querySelector(".lux-button");
  const toggle = document.querySelector(".elementor-menu-toggle");
  const menuLinks = document.querySelectorAll(".lux-navigation a");
  const headerNav = document.querySelector(".lux-navigation"); // Navigation container

  // Check if the key elements exist on the page
  if (header && logo && button) {
      
      ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
    // Create a timeline with ScrollTrigger
    let tl = gsap.timeline({
      scrollTrigger: {
        trigger: header,       // The header triggers the animation
        start: "top top",      // Starts when the top of the header is 50px above the viewport
        end: "+=300",          // Ends after the user scrolls 300px
        scrub: 1,              // Smoothly links the animation to the scroll position
        invalidateOnRefresh: true,
      },
    });


    // Use a fromTo animation for the height
    tl.fromTo(
      header,
      { height: "clamp(6.25rem, 3.205vw + 5.529rem, 9.375rem)" }, // Initial dynamic height, must match with CSS
      {
        height: "clamp(3.75rem, 3.205vw + 3.029rem, 6.875rem)", // Target height
        backgroundColor: "rgba(255, 255, 255, 0.3)", // Change background color
        backdropFilter: "blur(15px)", // Apply blur effect
        ease: "none", // No additional easing
      }
    );

    // Scale down the button
    tl.to(button, {
      scale: 0.8, // Shrinks the button slightly
      transformOrigin: "center center", // Shrinks from the center
      ease: "none", // Smooth transition without extra easing
    }, "<"); // Synchronize this animation with the previous one

    // Scale down the logo
    tl.to(logo, {
      scale: 0.7, // Shrinks the logo
      transformOrigin: "center center", // Shrinks from the center
      ease: "none", // Smooth scaling
    }, "<"); // Synchronize with the previous animation

    // Scale down the mobile menu toggle
    tl.to(toggle, {
      scale: 0.8, // Shrinks the toggle button slightly
      transformOrigin: "center center", // Shrinks from the center
      ease: "none",
    }, "<"); // Synchronize with the previous animation

    // Scale down the navigation container
    tl.to(headerNav, {
      scale: 0.8, // Shrinks the entire navigation container
      transformOrigin: "center center", // Shrinks from the center
      ease: "none",
    }, "<"); // Synchronize with the previous animation

    // Change the color of each menu link
    menuLinks.forEach((link) => {
      tl.to(link, {
        color: "#FFF", // Changes the link color to white
        ease: "power1.inOut", // Smooth easing for the color change
      }, "<"); // Synchronize with the previous animation
    });

  } else {
    // Log an error if one or more selectors are missing
    console.error("One or more key elements are missing from the page.");
  }
  
  window.addEventListener('resize', () => {
  ScrollTrigger.refresh();
});

</script>

CSS Code

Add this into the wrapper Container or better in the wordpress customizer or in your WordPress CSS

.lux-header {
  position: fixed; /* Sticks the header to the top of the viewport */
  top: 0; /* Aligns the header at the very top */
  width: 100%; /* Full width of the viewport */
  height: clamp(6.25rem, 3.205vw + 5.529rem, 9.375rem); /* Responsive height using CSS clamp */
  background: rgba(255, 255, 255, 0.2); /* Transparent white background */
  backdrop-filter: blur(10px); /* Applies a blur effect for a frosted glass look */
  display: flex; /* Flexbox layout for alignment */
  align-items: center; /* Centers items vertically */
  justify-content: space-between; /* Spaces items evenly */
  padding: 0 20px; /* Adds padding to the left and right */
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
  z-index: 1000; /* Ensures the header stays above other elements */
  transition: all 0.3s ease; /* Smooth transition for all properties */
  will-change: transform; /* Optimizes for transform animations */
}

.lux-logo img {
  width: clamp(6.25rem, 3.205vw + 5.529rem, 9.375rem);
  height: auto; /* Maintains aspect ratio */
  object-fit: contain; /* Ensures the image fits within its container */
  display: block; /* Removes extra spacing from inline images */
  transition: all 0.3s ease; /* Smooth transition for all properties */
  transform-origin: center center; /* Scales from the center */
  will-change: transform; /* Optimizes for transform animations */
}

.lux-navigation {
  display: flex; /* Flexbox layout for navigation links */
  justify-content: center; /* Centers links horizontally */
  align-items: center; /* Aligns links vertically */
  width: 100%; /* Full width for alignment */
  position: relative; /* Allows positioning of child elements */
  transform-origin: center center; /* Scaling from the center */
  transition: all 0.3s ease; /* Smooth transition */
}

.lux-navigation a {
  text-decoration: none; /* Removes underline from links */
  font-size: 1rem; /* Default font size */
  margin: 0px; /* Spacing between links */
  transition: font-size 0.3s ease, color 0.3s ease; /* Smooth transitions for size and color */
  will-change: transform, color; /* Optimizes for these properties */
  text-align: center; /* Centers text inside the links */
}

.elementor-menu-toggle {
  align-self: center; /* Vertically centers the toggle */
  font-size: 35px; /* Default font size */
  cursor: pointer; /* Changes cursor to pointer */
  transition: transform 0.3s ease; /* Smooth transition for scaling */
  transform-origin: center center; /* Scales from the center */
}

.lux-button {
  box-sizing: border-box; /* Includes padding and border in width/height */
  display: inline-flex; /* Flexbox for alignment */
  justify-content: center; /* Centers content horizontally */
  align-items: center; /* Centers content vertically */
  transform-origin: center center; /* Scales from the center */
  transition: transform 0.3s ease; /* Smooth scaling */
}

.lux-button a {
  display: inline-block; /* Allows padding and width adjustments */
  text-align: center; /* Centers text inside the button */
  padding: 10px 25px; /* Adds padding inside the button */
  white-space: nowrap; /* Prevents text wrapping */
  line-height: 1.5; /* Improves readability */
  transition: all 0.3s ease; /* Smooth transition for all properties */
}

.lux-icon {
  width: 30px; /* Default width for the icon */
  height: 2px; /* Height for the bars */
  background: #333; /* Dark gray color for the bars */
  display: block; /* Displays the icon as a block element */
  margin: 6px 0; /* Spacing between bars */
  transition: all 0.3s ease; /* Smooth transition */
}

/* Responsive adjustments */
@media (max-width: 1024px) {
  .lux-logo img {
    /* Adjust width for tablets */
    transition: all 0.3s ease; /* Smooth transition */
    transform-origin: center center; /* Scaling from the center */
  }

  .elementor-menu-toggle {
    font-size: 30px; /* Smaller toggle size for tablets */
    transition: all 0.3s ease; /* Smooth transition */
  }

  .lux-navigation a {
    font-size: 1.2rem; /* Larger font size for better readability */
    transition: all 0.3s ease; /* Smooth transition */
  }
}

@media (max-width: 767px) {
  .lux-logo img {
    /* Adjust width for mobile */
    transition: all 0.3s ease; /* Smooth transition */
    transform-origin: center center; /* Scaling from the center */
  }

  .elementor-menu-toggle {
    font-size: 30px; /* Adjust size for mobile */
    transition: all 0.3s ease; /* Smooth transition */
  }

  .lux-navigation a {
    font-size: 1.2rem; /* Default font size for links */
    color: rgba(30, 30, 30, 1); /* Darker link color */
    transition: all 0.3s ease; /* Smooth transition */
  }
}

What does this code do?

  1. Header Shrinking: Reduces the height of the header while adding a translucent background and a blur effect.
  2. Logo and Button Scaling: Scales down the logo and button for a more compact appearance.
  3. Navigation Scaling: Shrinks the entire navigation menu to match the smaller header.
  4. Menu Link Color Change: Changes the color of the menu links as you scroll for better contrast.
  5. Mobile Menu Toggle: Scales down the mobile menu toggle button to align with the overall shrinking effect.

Tips for Adjustements:

  • start and end values: Adjust these values to control when the animation begins and ends.
  • Custom Colors: Replace #FFF with any color code to match their design.
  • Scrub Setting: Experiment with scrub: 1 to fine-tune the scroll-linked animation smoothness.
GDPR Cookie Consent with Real Cookie Banner