Jump to content
Search Community

change each nav-item color in a fixed vertical side menu according to the section background-color behind it

una test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hi,

I am trying to change each nav item color from white to black or back depending on the section class (i.e background color) behind it.
The navigation is fixed as the content comprised of sections with class="section-white" or class= "section-dark" scrolls beneath it.
The script below changes all links simultaenously. Has anyone any suggestion as to what I am doing wrong?
Thanks!

const sections = gsap.utils.toArray('.section-white');
sections.forEach(section => {	  
	 ScrollTrigger.create({
		 trigger: section,
		 duration:3,
		 start: 'top 300px',
		 end: 'bottom 80px',
		 scrub: 1,
        toggleClass: {
			 targets: '.nav-link',
			 className: 'text-black'
		 },
		 markers: true,
	 })	 
 });
 

 

See the Pen rNRQrvm by fatcatsanonymous (@fatcatsanonymous) on CodePen

Link to comment
Share on other sites

Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependancies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

Hi, Thanks for this tip.
I did watch this tutorial already actually,  but it doesn't solve my issue unfortunately.

I added a codepen above to show where I'm at. The nav item color is changing but I would like each instance to change as it enters the section. Otherwise, as the user scrolls and is halfway through the navigation you have white links on white background.

 

Link to comment
Share on other sites

22 hours ago, una said:

The script below changes all links simultaenously. Has anyone any suggestion as to what I am doing wrong?

Right now you only loop through the sections, but you want to change the .nav-link one by one, so you need another loop that does this but then for each .nav-link, this does mean that we're creating as many ScrollTriggers as there are sections * .nav-link items, which means there are a lot!

 

You do have to calculate the offset of each .nav-link I now used some random fixed values which are good enough to show in the demo and explain the concept, but you probably want to get that dynamically so that it is more robust on different screen sizes. 

 

There is probably a better way of doing this. A timeline animation with a stagger what just changes each .nav-link color one by one instead of a class and than setting the ScrollTrigger to scrub: true, so that it plays the animation on scroll, but that is why Codepen is great. Personally I use codepen to try out new ideas, I usually then just keep forking my pen to try out different ideas, either because I think it could be better or my original idea was not working. Usually at version 10 I got something I'm happy with. Creating forks of your pen will allow you to fall back at earlier ideas if something new is not working.

 

See the Pen poYqNPx?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

 

In this case if you're not going to animate things why not just set   mix-blend-mode: difference; in CSS I'm not sure if there is a better blend more for  the colors you use, but this gets you 90% there  for free. 

 

See the Pen zYbyopO?editors=0100 by mvaneijgen (@mvaneijgen) on CodePen

  • Like 3
Link to comment
Share on other sites

Hi mvaneijgen,

Thanks so much for this. I don't quite understand the offset though. Regardless how I set these values, The markers are not in line with the nav items...
Regarding mix-blend-mode, I had thought of using this as a simple solution too, however as it is a fixed navigation  above not within the background sections,  the background-colors of the sections have no relation to it so this won't work. 
As I have GSAP incorporated anyway for other animations it seemed the best solution to use it for the nav also.

I'll post the results.

  • Like 1
Link to comment
Share on other sites

  • Solution

Hi,

 

I checked your last demo and it seems to be working as expected. What exactly is the issue you're having?

 

I forked your demo and instead of using hardcoded values for each element's offset I used the getBoundingClientRect method:
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

 

This is a fork of your latest demo:

See the Pen mdoNxoe by GreenSock (@GreenSock) on CodePen

 

Hopefully this helps.

Happy Tweening!

  • Thanks 1
Link to comment
Share on other sites

Hi Thanks so much for this. The fixed values were exactly my issue. @mvaneijgen kindly helped me out with the second loop which was my initial problem.
So many thanks to both of you for your expertise and help!

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

You need to wait until it has fully opened and then call ScrollTrigger.refresh();

 

If you build the toggle with GSAP you can hook it in the onComplete callback of the tween. How you've set it up now I don't know how you would do that, maybe there are jQuery hooks you can use, but I can't advise you on that. But that said you've GSAP super powers now, so simply changing a class is a bit simple, right? You've of course want to build an animating with each item staggering in one by one anyway! 

Link to comment
Share on other sites

Yeah, you should do that here after toggling the class:

$("ul li.dropdown").on("click", function () {
  $(this).toggleClass("show-dropdown-menu");
  ScrollTrigger.refresh();
});

Finally is worth noticing that this is not going to work:

const navLinks = gsap.utils.toArray(".nav-link");
navLinks.addEventListener("click", (event) => {
});

The navLinks constant is an array and you can't attach an event listener on an array:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

 

Happy Tweening!

Link to comment
Share on other sites

Thanks to you both - you're so fast!
I had tried adding  the Scrolltrigger.refresh to the toggle function but this doesn't work somehow. I assume also it will refresh all scrolltrigger markers from other animations on the page in question, which is not great either.

I guess I'll look into using GSAP to rebuild the menu dropdown and go from there. ... haven't really figured outhow to tap into those superpowers that I now have, though!

Link to comment
Share on other sites

Hi,

 

Since you have an array with all the sections that you loop trough to create the ScrollTrigger instances, you can store those ScrollTrigger instances in another array, in order to loop through and refresh just those:

const stArray = [];

sections.forEach(() => {
  navLinks.forEach((item, index) => {
    const rect = item.getBoundingClientRect();
    stArray.push(ScrollTrigger.create({
      trigger: section,
      start: `top ${rect.y}`,
      end: `bottom ${rect.y + rect.height}`,
      scrub: 1,
      toggleClass: {
        targets: item,
        className: "text-black"
      },
      markers: true
    }));
  });
});

Then in your code:

$("ul li.dropdown").on("click", function () {
  $(this).toggleClass("show-dropdown-menu");
  stArray.forEach((st) => st.refresh());
});

Happy Tweening!

  • Like 2
Link to comment
Share on other sites

When you use function based values and call ScrollTrigger.refresh() these values get recalculated. If you don't use function based values, but use functions in your values, ScrollTrigger will think they do not update and keeps the values it has calculated on initial load. 

 

I've also moved the item.getBoundingClientRect() in to the value, to be sure it recalculates the values. Hope it helps and happy tweening! 

 

See the Pen ZEZOOEv?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

  • Like 2
Link to comment
Share on other sites

... works a dream! Thanks again to you both, not only for your generous work on solutions, but also for the informative insights on working with GSAP! 

  • Like 1
Link to comment
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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...