JavaScript colour change on scroll

So when I first started this blog I didn’t really do much in terms of design because I wanted to start using it straight away (so yes it still has bugs and is bad and I’m sorry). One thing I did do was a JavaScript/jQuery thingy that makes the heading and category change colour as you scroll. The idea is that when the post is at the bottom of the page the heading is grey, as you scroll up it changes to bright green, as it’s now the active post. There is quite likely a jQuery plugin that you could find to do this, but I wanted to write it for JS practice and I liked doing it because I got to do maths so by the end of it I had a piece of paper filled with crazy person scribbles. For some reason that makes me happy.

So if you are reading this and I’ve removed it from the blog or you just want to see it without any clutter there is a demo here.

If you just want the code, here it is, otherwise keep scrolling and I will explain how it works.

$(document).scroll(function() {  
    var element = $(this), 
      fromTop = element.offset().top - $(window).scrollTop(),
      // minus 100 because 100px from the top is where the element should be at full colour
      // divide by 300 because the height of the transition area is 300px, ie when more than 400px from the top the heading will be grey
      percentFromTop = (fromTop - 100) / 300;
    var chStart=[196, 193, 185]; // grey
    var chEnd=[54, 215, 0]; // green
    var chDiff=[chStart[0] - chEnd[0], chStart[1] - chEnd[1], chStart[2] - chEnd[2]];    
    var chTrans = [Math.round(chDiff[0] * percentFromTop) + chEnd[0], Math.round(chDiff[1] * percentFromTop) + chEnd[1], Math.round(chDiff[2] * percentFromTop) + chEnd[2]];
    if (fromTop > 401 ) {
      element.find('.postCategory').css('background-color','rgb(' + chStart[0] + ', ' + chStart[1] + ', ' + chStart[2] + ')');
      element.find('h2 > a').css('color','rgb(' + chStart[0] + ', ' + chStart[1] + ', ' + chStart[2] + ')');
    if (fromTop < 400 && fromTop > 101) {
      element.find('.postCategory').css('background-color','rgb(' + chTrans[0] + ', ' + chTrans[1] + ', ' + chTrans[2] + ')');
      element.find('h2 > a').css('color','rgb(' + chTrans[0] + ', ' + chTrans[1] + ', ' + chTrans[2] + ')');
    if (fromTop < 100 ) {
      element.find('.postCategory').css('background-color','rgb(' + chEnd[0] + ', ' + chEnd[1] + ', ' + chEnd[2] + ')');
      element.find('h2 > a').css('color','rgb(' + chEnd[0] + ', ' + chEnd[1] + ', ' + chEnd[2] + ')');

The area of the page that the transition takes place is between 100px and 400px from the top (in the demo this is the area that has the grey background). I will refer to this as the transition zone (I would prefer danger zone but it would get confusing as no danger is involved). So when the heading is 100px from the top the colour will be at full strength, when it is below 400px it will be grey.

When you scroll it calculates how far from the top the each post is, then how far through the transition zone it is, this is stored in the percentFromTop variable.

You put a starting rgb value in an array: var chStart=[196, 193, 185]; and an ending one: var chEnd=[54, 215, 0];.

The difference between the starting and ending colour for each colour channel is calculated in var chDiff. The rgb colour that should be used during the transition is then calculated in var chTrans.

After that it’s just some if statements that see where the element is to decide what colour to use. If it’s below 400px from the top it uses the starting colour (grey), if it’s above 100px it uses the ending colour (green) and if it’s between those it’s in the transition zone so uses the colour that was just calculated with all those variables and crazy things.


I know there is a lot of repeating so I’m sure this could get compressed a lot. I was thinking of having different colours for the different categories, if I do this I will probably look at changing it then as it currently can’t handle more than one colour change. The other thing that’s missing is that there is no colour set on page load, only on scroll. I got around this by setting the heading colour to green in the css. I figured that my posts would always be at least the height of the window since I like using pictures, so it would be unusual for there to be an instance when there would be two headings visible on the page when it loads. Hopefully I will write that at some point though.