Change Background gradient horizontally on scroll down

I’m trying to figure out how to change the background gradient of a section (.header) as the user scrolls down.
Here is the background gradient:
background: linear-gradient(90deg, rgba(0, 49, 84, .8) 0%, rgba(154, 198, 229, 1) 100%);

Ultimately I want to change the percent from 0 to 100 as the user scrolls past it creating a wave affect.

Here is a codepen


If you want a dynamic effect then this is mainly a js question as you will need to tie into the scroll event and change the gradient based on how far the user has scrolled.

I’m not sure if this is what you meant (and I just borrowed the js from elsewhere) but here’s an example.

It sounds as though its a question for the JS forum rather than CSS so you can get better advice :slight_smile:

Moved it!


Yes. This is exactly what I was looking for. Thank you! However, when I try and implement it as in the code pen it’s not working. I’ve got the js in the footer, and it’s writing the y scroll number to the console so I know that part is working. The css variable part is were it’s breaking. Is there anything special I need to do on the that side? I haven’t used variables in css much.

<style type="text/css">
:root {
  --gradient-percent: 0%;

.header {
  position: relative;
  text-align: center;
  background: linear-gradient(90deg, rgba(0, 49, 84, .8) var(--gradient-percent), rgba(154, 198, 229, 1) 100%);
  color: white;


Here’s a link to the dev site

I think its a cross origin issue with the stylesheet. I think it can only read the ones that come from your domain and any others throw an error. If possible try temporarily commenting out any stylesheet from other domains just to see if this is the issue.

I’m not sure how to get around it other than writing the style directly with js rather than the easier way of updating the css variable.

Hopefully one of the JS gurus around here can shed some light on it perhaps ?(@James_Hibbard or @Paul_Wilkins or anyone :slight_smile: )

Morning :slight_smile:

I’m on the hop, so I didn’t look at this in any depth, but I see one CORS error when I look at the console on that page:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at (Reason: CORS request did not succeed).

Is that what we are talking about?

If so, do things work as expected if you copy/paste the contents of into the page (instead of including it in a script tag)?

There are also quite a lot of errors on the page you link to:

TypeError: $ is not a function
ReferenceError: dsidx is not defined
TypeError: $ is undefined
TypeError: $(...).select2 is not a function
ReferenceError: AOS is not defined

I would be inclined to sort those out to exclude the fact that things are breaking in an unexpected place.

1 Like

Hi @aaron4osu, from looking at the computed properties in the element inspector the variable is getting updated fine; however the values don’t look right, e.g.

.header {
  background-image: linear-gradient(60deg, rgb(0, 49, 84) 14036px, rgb(154, 198, 229) 100%);

Or you sure you’re using the desired formula and unit here?

window.addEventListener('scroll', () => {
  const y = 1 + (window.scrollY || window.pageYOffset);'--gradient-percent', y * 4 + "px");

E.g. if you want to get the percentage the viewport has been scrolled down, this should do the trick:

window.addEventListener('scroll', () => {
  const y = window.scrollY / document.body.scrollHeight'--gradient-percent', y + '%')

BTW I’d also suggest to wrap the calculation and update in an animation frame request, as doing so right on every scroll event can quickly lead to yanking:

window.addEventListener('scroll', () => {
  window.requestAnimationFrame(() => {
    const y = window.scrollY / document.body.scrollHeight'--gradient-percent', y + '%')

Thanks for chiming in as JS is not my strongpoint (as you know) :slight_smile:

Yes I was going to say that the routine needed to be throttled in some way.

I think what also needs to happen is that the gradient is only started to be updated when the element in question is visible in the viewport. Also the 0 - 100% of the linear gradient should be calculated on the scroll height of the element so it completes a full sweep as the element scrolls up or down.

The codepen demo of mine above was just a simple proof of concept and of course the element in question is already visible at the top of the viewport and so the routine works ok. In a real situation it gets a bit more complex :slight_smile:

1 Like

Ah sry I didn’t even realise this was the JS from your pen – which is obviously working fine, it just shows once again that simply copy / pasting some demo code to your web page will rarely yield the expected results. ^^

Yes good points! The full sweep could be addressed by calculating the gradient from getBoundingClientRect().top / window.innerHeight and setting the CSS variable in the scope of the element, and accounting for visible elements could be done using the intersection observer API; here’s another demo (! haha) bringing it all together:

PS: I’m not sure though if using an intersection observer is really necessary here… the browser might be clever enough not to bother updating elements outside of the viewport anyway.


Nice work :slight_smile:

1 Like

Thanks!!! I really appreciate the time you guys must have spend on this. works perfect now.

1 Like