2012-08-15

"Sticky" blocks in Pure Javascript

I needed a "sticky div" on a website I've been working on. In other words a block that sticks to the top of the window when the page is scrolled down, so that it will remain visible at all times. Unfortunately, all the examples I found required jQuery.  Scouring the 'net I found nothing in pure javascript...

It's a shame that something a few lines long needs an external library to accomplish nowadays. Eventually, after digging and digging I did find this example straight out of the predotcombrian era.  Horrible markup and code.  The block also snapped back into place only when the window is scrollled all the way to the top.  But, you've got to hand it to the guy, it worked.

So, I updated some of the ancient constructs, refactored a few things,  and did a bit of an all-around cleanup.  It undoubtedly could be modernized further, but I'm stopping here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Sticky DIV</title>
    <style type="text/css">
        body {
            background-color: #222;
            height: 2000px;
        }
        .stickydiv {
            border: 2px solid #800;
            color: #aaa;
            font-family: arial;
            height: 15em;
            padding: 1em;
            width: 31ex;
        }
    </style>
    <script>
        var origypos = 0;

        function byid(idname) {
            return document.getElementById(idname);
        }
        function get_pos(obj) {
            var pos = [0,0];
            while(obj) {
                pos[0] += obj.offsetLeft;
                pos[1] += obj.offsetTop;
                obj = obj.offsetParent;
            }
            return pos;
        }
        function get_offset() {
            // supports for < IE9
            var top = document.body.scrollTop;
            if (window.innerHeight) {
                top = window.pageYOffset;
            }
            else if (
                document.documentElement.clientHeight) {
                top = document.documentElement.scrollTop;
            }
            return top;
        }

        window.onscroll =  function() {
            var sticky = byid('sticky'),
                pos = get_pos(sticky),
                off = get_offset(),
                ypos = origypos || pos[1];  // > 0
            console.log('pos:', pos[1], ' / off:', off,
                ' / oyp:', origypos);

            if (off > ypos) {
                sticky.style.position = 'fixed';
                sticky.style.top = '.2em';
                sticky.style.boxShadow =
                    '1ex 1ex 2ex rgba(0,0,0,.5)';
                console.log('pop-out!');
            } else {
                sticky.style.position = 'static';
                sticky.style.boxShadow = 'none';
                console.log('in');
                if (!origypos) {  // reset only when zero
                    origypos = pos[1];
                }
            }
        }
    </script>
</head>

<body>
    <br>
    <br>
    <br>
    <hr>
    <div id="sticky" class="stickydiv" >
        I am always on top.
    </div>


</body>
</html>

Comment out those console.logs when satisfied. If you don't need to support older IE releases you could replace the whole get_offset() function with window.pageYOffset.

1 comment:

  1. Genial! si me funciono *-*

    lo uso aqui: http://purosgifs.blogspot.com

    ReplyDelete