Background Gradient change on scrolling + transition with JS

Hello everyone,
java script is a new area for me but i’m working my way through it. I’m stuck right now and just can’t get any further.

I would like the background to change depending on the position when scrolling. The whole should have several color gradients and a smooth transition between the changes. I get the gradients, but not the smooth transition.

var body = document.getElementsByTagName(‘body’)[0];
body.style.background = ‘linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(214,20,20,1) 100%)’;

    // trigger this function every time the user scrolls
    window.onscroll = function (event) 
			
			{
        var scroll = window.pageYOffset;
        if (scroll < 300) {
         
           body.style.background = 'linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(28,255,9,1) 100%), transition: background 5s ease';
					} 
				
				 
				else if (scroll >= 300 && scroll < 600) {
        
            body.style.background = 'linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(171,156,46,1) 100%), transition: background 5s ease';
						
        } 
				
				else if (scroll >= 600 && scroll < 1200) {
        
            body.style.background  = 'linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(46,161,171,1) 100%), transition: background 5s ease';
        } 
				
				else if (scroll >= 1200 && scroll < 1800) {
       
            body.style.background  = 'linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(171,46,89,1) 100%)';
        } 
				
				else if (scroll >= 1800 && scroll < 3000){
						  body.style.background = 'linear-gradient(0deg, rgba(63,94,251,1) 0%, rgba(171,46,89,1) 100%)';
       	} 
    } 

;

I am not on my laptop to test this, but I wonder if we can use a CSS Custom Property for the color part of a gradient and animate its value depending on where in the page you are.

Take a look at this example from a few years ago that highlights how you can do this:

You get the best of both worlds here. The animation itself is handled by the CSS transition. The value change is handled by JavaScript where the CSS custom property is modified.

I haven’t had a chance to do a writeup, but I explain in towards the end of this video on how something like this works:

Taking a step back, animations created in JavaScript can be 99% as performant as animations created in CSS. The downside on slower devices is that there will be a small penalty from having to actually run the JavaScript.

:space_invader:

You are totally right! I thought the custom prop approach would work around that, but it doesn’t for the reason you outlined. Here is what my failed attempt looks like:

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Changing Background Colors</title>

  <style>
    body {
      --gradientStop: rgba(28, 255, 9, 1);

      background: linear-gradient(0deg, rgba(63,94,251,1) 0%, var(--gradientStop) 100%);
      transition: background .5s ease;

      height: 3000px;
    }
  </style>
</head>

<body>
  <script>
    document.addEventListener("scroll", throttleEvent, false);

    let isFiring = false;

    function throttleEvent(event) {
      if (isFiring === false) {
        requestAnimationFrame(() => {
          handleScrolledPosition(event);
          isFiring = false;
        });
      }
      isFiring = true;
    }

    function handleScrolledPosition(event) {
      let scroll = window.pageYOffset;

      if (scroll < 300) {
        document.body.style.setProperty("--gradientStop", "rgba(28, 255, 9, 1)");
      } else if (scroll >= 300 && scroll < 600) {
        document.body.style.setProperty("--gradientStop", "rgba(171, 156, 46, 1)");
      } else if (scroll >= 600 && scroll < 1200) {
        document.body.style.setProperty("--gradientStop", "rgba(46, 161, 171, 1)");
      } else if (scroll >= 1200 && scroll < 1800) {
        document.body.style.setProperty("--gradientStop", "rgba(171, 46, 89, 1)");
      } else if (scroll >= 1800 && scroll < 3000) {
        document.body.style.setProperty("--gradientStop", "rgba(171, 46, 89, 1)");
      }
    }
  </script>
</body>

</html>

Let me see if there is another hack that may work here involving gradient stops!

Thank you for your time and the interest in finding a solution :blush:

So it’s still not possible to simply add the transition property to a background gradient?

I simplyfied the code a bit and added different colour gradients to not confuse. The colour is not important right now, but the combination of gradient + change when scroll + smooth transition. The transiton works fine with solid colours but doesnt with gradient.

BTW, this is the effect I want to create, maybe it helps if you have a lock at the code:

Here is the code

https://replit.com/join/iuixavdlsu-mihneagrosu

I’m trying to see if animating the background-position can help create this effect. It doesn’t look too convincing, but here is what this attempt looks like:

It looks like that demo page (simone sneakers) uses intersection observer to swap the backgrounds at certain breakpoints rather than linking animation percentages to scroll.

The elements scroll the background until the breakpoint…

The animation is trigger on the background swap…

I haven’t done anything with gradient animation but I know that SVG SMIL can do gradient animations with <animate>

I haven’t looked into it but Element.animate( ) may do gradients.
It does play and pause pretty well…

1 Like

PAEz my dear friend, thank you very much for the effort. I took a quick look at your code last night, I was too tired to respond, but found it very promising. why did you delete your post? I would have liked to try it.

I’m currently building the website with wordpress+elementor. That’s why I have to unravel it a bit and rethink which elements I can use the “block” class for, for example.

As you know, I’m not very well versed in javascript, so I wanted to ask you why you used gradient-mask and why the 1st block in the html code was written in rbga and not like the others in hex?

maybe you can upload the code again?

cheers

The gradient mask was used because as I explained in a previous comment you cant animate css gradients, but you can animate a single colour from one to another. So the mask is used to create a gradient by making the colours transparent to what ever degree so that the other colour comes through creating the gradient effect. Then we can just animate the two colours and you get the effect you where looking for.
The rgba is just to show you can, I was going to explain that and got tired myself. You can use any css colour type.
You can use pretty much any element that is visible (maybe even not visible?). The idea is once it gets to a certain point in the page then colours will change to what is set in data-bgFrom and data-bgTo. As long as the element has those two attributes on it then it will do its thing. It doesnt have to have a class of block or anything else, thats just to make the blocks for demonstration purposes.
Im actually not happy with the way its deciding when to change and was thinking of changing the code for that bit. The way it is now its a bit to specific on the size of things so I might change that, but I cant promise anything till saturday/sunday for reasons.
To use it in another page you should just be able to add the script and the section of css inside the remarks I just added to it. I just changed the script to make sure it wont pollute the global space or anything.

And Im sorry for deleting the posts, didnt mean to cause you any grief. Ive got problems and this site is adding to them. I dont know how to deal with things and just wanted to scrub it all. Dont like the idea that its affecting someone else so I dunno, never do. Thanks tho aye.

Link… GradientScrollPosition4 - Replit