2

In my webapplication I have this background which is made out of 2 linear gradients I want to change the "inclination" of the gradient based on a scroll

I don't really have an idea of how to do this...

this is the current state: https://prnt.sc/no3las (so I would like to animate the blue background thins on scroll :-) )

This is the css of the background of my site

html {
  font-family: 'Roboto Mono', monospace;
  background: linear-gradient(70deg, #5870cb 20%, rgba(0, 0, 0, 0) 1%), 
              linear-gradient(20deg, white 85%, #5870cb 2%);
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-attachment: fixed;
  height: 100vh;
}
tao
  • 82,996
  • 16
  • 114
  • 150
Tijs Martens
  • 266
  • 2
  • 10
  • 3
    Please share your best attempt at coding this. Without it, or without at least a significant documentation effort, you are not, by definition, a programmer, but a client. Which makes your question *off-topic* on this website. Please read [ask]. In particular, you want to use JavaScript to gradually change the `background` value of your element based on value of `scrollTop`, inside a function bound on window's `scroll`. – tao May 13 '19 at 20:05
  • I actually have no idea how to start with this. I did some research on scroll libraries like scrollmagic (https://scrollmagic.io/) and laxxx (https://github.com/alexfoxy/laxxx) but they both don't seem to be able to modify the background property.. It would be a great help if someone could give me resource so I can figure it out on my own. I don't expect you to send me code that i can copy... – Tijs Martens May 13 '19 at 20:32
  • I am trying to modify these values on scroll.... background: linear-gradient(**70deg**, #5870cb 20%, rgba(0, 0, 0, 0) 1%), linear-gradient(**20deg**, white 85%, #5870cb 2%);`` – Tijs Martens May 13 '19 at 20:35
  • Which way do you want it to animate? Every way to "modify these values" is different and some could be VERY difficult. – nCoder May 13 '19 at 22:41

2 Answers2

3

To rotate a gradient you need to understand (and deconstruct) the linear-gradient (which is, in fact, a background-image). A good rundown can be found on MDN and the official spec is on CSSWG (W3C).

The first thing to know about it is that you can't move it's center. Since it is the element's background, the center of the gradient will always be the center of the element.
Note: If your design requires different rotation centers, you can always use more than 1 element and size them accordingly.

Now, let's assume you want to rotate the first gradient from 70deg to 110deg and the second one from 20deg to 155deg.

A quick search for scroll event will (hopefully) get you on MDN's page, which has an example.

Coupling it with the above, you get something along these lines (I placed the logic for rotating the backgroundImage inside the example's doSomething function).

I've also specified where I've taken each bit from, to show how to go about documenting your question, step by step. Point here being: every bit you can do yourself, do it and only leave out the bits you don't know.

let last_known_scroll_position = 0;
let ticking = false;

// helpers
const body = document.querySelector('body');
const html = document.querySelector('html');

function doSomething(scroll_pos) {

 // from https://stackoverflow.com/a/1147768/1891677 :
 const bodyHeight = Math.max( body.scrollHeight, 
                              body.offsetHeight, 
                              html.clientHeight, 
                              html.scrollHeight, 
                              html.offsetHeight);
 
 // from https://stackoverflow.com/a/8876069/1891677 :
 const viewportHeight = Math.max(document.documentElement.clientHeight,
                                 window.innerHeight || 0);
 
 // set scrollPercentage, if we have available scroll (0 otherwise):
 const availableScroll = bodyHeight - viewportHeight;
 const percentage = availableScroll > 0 ? scroll_pos * 100/availableScroll : 0;
  
 // this is what the question is about:
 const fromPercent = (from,to,current) => ((to - from) * current/100) + from;
 body.style.backgroundImage = `
 linear-gradient(${fromPercent(70, 110, percentage)}deg, #5870cb 20%, rgba(0,0,0,0) 0),
 linear-gradient(${fromPercent(20, 155, percentage)}deg, white 85%, #5870cb 2%)
 `;
}

// rest of example, from MDN:
window.addEventListener('scroll', function(e) {
  last_known_scroll_position = window.scrollY;

  if (!ticking) {
    window.requestAnimationFrame(function() {
      doSomething(last_known_scroll_position);
      ticking = false;
    });

    ticking = true;
  }
});
body {
  font-family: 'Roboto Mono', monospace;
  background-image: linear-gradient(70deg, #5870cb 20%, rgba(0,0,0,0) 1%), 
                    linear-gradient(20deg, white 85%, #5870cb 2%);
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-attachment: fixed;
  height: 300vh;
}
tao
  • 82,996
  • 16
  • 114
  • 150
  • Thak you! It worked perfectly, I Had to change one thing. My background is set on the html tag and not the body tag. so i had this : ``` const fromPercent = (from,to,current) => ((to - from) * current/100) + from; html.style.backgroundImage = ` linear-gradient(${fromPercent(70, 110, percentage)}deg, #5870cb 20%, rgba(0,0,0,0) 0), linear-gradient(${fromPercent(20, 155, percentage)}deg, white 85%, #5870cb 2%) `; }``` thanks ! (this is the result: https://gyazo.com/fecc130facf6b35771302866c4047aad) – Tijs Martens May 14 '19 at 06:34
  • I will take your advise about SO for future questions, also thanks for that – Tijs Martens May 14 '19 at 06:37
1

Basically, what you need is the current scroll position (via .scrollTop) as well as the maximum scroll distance (<SCROLLING_ELEMENT>.scrollHeight - window.innerHeight). If you have these infos, you can calculate the rotation/angle of the gradient with a bit of JS easily:

// HTML :: Element
const HTML = document.documentElement;

// getCurrentScroll :: () -> Number
const getCurrentScroll = () => HTML.scrollTop;

// getMaxScroll :: () -> Number
const getMaxScroll = () => HTML.scrollHeight - window.innerHeight;

// calcRotation :: (Number, Number) -> Number
const calcRotation = (pos, max) => pos / max * 360;

// getBG :: Number -> String
const getBG = r => `linear-gradient(${r + 70}deg, #5870cb 20%, rgba(0,0,0,0) 1%), linear-gradient(${r + 20}deg, white 85%, #5870cb 2%)`;



document.addEventListener('scroll', () => {
  const rot = calcRotation(getCurrentScroll(), getMaxScroll());
  HTML.style.backgroundImage = getBG(rot);
});
html {
  font-family: 'Roboto Mono', monospace;
  background: linear-gradient(70deg, #5870cb 20%, rgba(0, 0, 0, 0) 1%), 
  linear-gradient(20deg, white 85%, #5870cb 2%);
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  background-attachment: fixed;
  height: 100vh;
  overflow: auto; /* no scrolling without this line */
}

body { height: 200vh; } /* just to create a scroll bar */
David
  • 3,552
  • 1
  • 13
  • 24