Skip to content

Make the background gradient(radial) move on scroll using css and js

So what I was looking for is a subtle radial gradient background effect which will move from left to right when the page is scrolled, like this site – https://hellonesh.io/ . So when I inspected the code of that site, I found the responsible HTML and CSS for that effect –

HTML

<body>
<main>

  <div class="bg" style="background-image: radial-gradient(88.33% 60.62% at 100.87% 48.33%, rgb(86, 53, 173) 0%, rgb(20, 9, 78) 100%);"></div>

  <section id="sec-1">
    ...
  </section>
  <section id="sec-2">
    ...
  </section>
  <section id="sec-3">
    ...
  </section>

</main>

<script>

  //  Need help here

</script>
</body>

CSS

.bg {
    position: fixed;
    display: block;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
}

section {
    height: 100vh;
}

jQuery/js

$(window).on('scroll', function () {
    //When a new section(100Vh) comes into view move the radial gradient left to right or right to left
    // completely lost here
    // $('.bg').css({background-image: "radial-gradient()"});
});

But I’ve no idea how to make the radial gradient move in the viewport when scrolled. If it’s a plugin please let me know the name. If not then how can I achieve that effect using JavaScript or jQuery? Thanks!

Answer

There are two parts to this question: how to sense when another section comes into view and when it does how to move the background image depending on which section is now in view.

For the first we can use InterSectionObserver. If we attach the observer to each section, it will get fired when that section comes into (or goes out of, but we aren’t interested in that) the viewport.

For the second, this snippet uses a CSS variable –x to say where the background image radial gradient is to have its ‘at’ x coord set. I don’t know what values you want for each section, so this snippet just looks at the id of the section that is in view and calculates the offset just for the demo.

function callback(entries) {
  entries.forEach( entry => {
    if (entry.isIntersecting) {
      let x = 50 * Number(entry.target.id.replace('sec-', '') - 1); //change to whatever you want the x to be for sec-n
      bg.style.setProperty('--x', x + '%');
    }
  });
}

const bg = document.querySelector('.bg');
const sections = document.querySelectorAll('section');
const observer = new IntersectionObserver(callback);

sections.forEach( section => {
  observer.observe(section);  
});
.bg { 
    --x: 0;
    --y: 48.33%;
    position: fixed;
    display: block;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-image: radial-gradient(88.33% 60.62% at var(--x) var(--y), rgb(86, 53, 173) 0%, rgb(20, 9, 78) 100%);
}

section {
    height: 100vh;
}
<main>

  <div class="bg"></div>

  <section id="sec-1">
    ...
  </section>
  <section id="sec-2">
    ...
  </section>
  <section id="sec-3">
    ...
  </section>

</main>