3

I wrote this sticky div effect in Jquery but was wondering a way to do the same thing with vanilla javascript

.stick {
    position: fixed;
    top: 0;
}



$(document).ready(function () {  
  var top = $('#a8').offset().top;
  $(window).scroll(function (event) {
    var y = $(this).scrollTop();
    if (y >= top)
      $('#a8').addClass('stick');
    else
      $('#a8').removeClass('stick');

  });
});
Alex Borsody
  • 1,908
  • 9
  • 40
  • 74

3 Answers3

5

Sure you can do the same in pure JS. Here is simple example:

var top = document.getElementById('a8').offsetTop;

window.onscroll = function() {
    var y = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
    if (y >= top) {
        a8.className = 'stick';
    }
    else {
        a8.className = '';
    }
};

Demo: http://jsfiddle.net/hd3uyf68/1/

Note, that in this simple example I don't actually implement addClass/removeClass functionality. If you need it it's quite easy to add.

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • Very nice! However, as I tried to implement this in my code, it was not working so I ended up opening [a question](http://stackoverflow.com/questions/41589733/javascript-working-in-fiddle-but-not-in-own-page-even-if-script-is-at-the-botto): naming the variable `top` is ambiguous, so another name would be preffered. – J0ANMM Jan 11 '17 at 12:09
  • It didn't work in your case because you were defining variable in global scope, while in my case it's a local variable. But yea, `top` is not very good name. – dfsq Jan 11 '17 at 12:20
  • Great, now it is solved. I created an answer with an adaptation of your code, which for my case works better. Maybe you have an idea of how to avoid the small 'jump' it is still doing? – J0ANMM Jan 12 '17 at 11:54
4

In vanilla JavaScript:

function ready() {
    var box = document.getElementById('box'),
        top = box.offsetTop;

    function scroll(event) {
        var y = document['documentElement' || 'body'].scrollTop;

        if (y >= top) box.classList.add('stick');
        else box.classList.remove('stick');

    }

    window.addEventListener('scroll', scroll);
}

if (document.readyState == 'complete' || document.readyState == 'loaded') {
    ready();
} else {
    window.addEventListener('DOMContentLoaded', ready);
}

JSFiddle example:

http://jsfiddle.net/869fqgds/4/

Community
  • 1
  • 1
Miguel Mota
  • 20,135
  • 5
  • 45
  • 64
0

Here is an adapted version from dfsq's answer, which is the most elegant and simple solution I've found so far:

    var myTop = document.getElementById('freeze').offsetTop;
    var origClass = freeze.className;
    window.onscroll = function() {
        var y = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
        if (y >= myTop) {
            freeze.className = origClass +' stick';
        }
        else {
            freeze.className = origClass;
        }
    };

// Note that I barely have javascript knowledge, so the modification, even if it works, might be far from optimal. I'm open to improvements.

Main differences are:

  • variable name changed to avoid ambiguity (see comments of that answer).
  • additional variable and modification inside if/else in order to allow using it with tags with an existing class already assigned.

The only issue remaining is that at the moment when the div is fixed, there is a kind of 'jump' in the flow. This is easily seen in the original jsfiddle if adding any text (for instance <p>See how I jump!</p>) a few lines below the div that is sticked.

Community
  • 1
  • 1
J0ANMM
  • 7,849
  • 10
  • 56
  • 90