Parallax Effect – Scrolling a Box Using jQuery

In here, I will show you how to use a parallax effect of scrolling a box using jQuery. Parallax came a few months ago and is already on the way out of the web world. At the same time, the concept I am discussing can be used for anything you want to pamper your webpage with. So, if you are still interested, please bear with me.

I based this code on Andy Shora’s article and the idea to have an array for the elements the may be moved during scrolling. His code though has too many things that are not critical for the movement, so I felt I need to improve it.

This here is what you can expect. What we play with is the CSS position attribute making it fixed when we need to keep it on the page and relative – when we want it to move with it.

We start with a blank HTML page like this:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Parallax Test - Scroll a Box</title>
   <style>
   </style>
   <script>
   </script>
</head>
<body>
   <section style="min-height: 600px;">
      <h3 style="text-align: center;">Scroll down</h3>
   </section>

   <section class="parallax1">
      <div class="parallax brick" data-id="brick-1" data-start="500" data-stop="960">
         MOVING BOX
      </div>
   </section>

   <section>
      <h3 style="text-align: center; margin-top: 550px">Scroll up</h3>
   </section>
</body>
</html>

At this point, you will see three sections. They are only to make the page long enough to show scroll bars. The middle one will be the one with a bar inside a large rectangle. to make it look like that though, we need to expand the <style></style> line as follows:

<style>
.bar {
   padding: 10px 0 0 0;
   margin: 0 auto;
   background-color: coral;
   display: inline-block;
   position: relative;
   top: 0;
   width: 300px;
   height: 30px;
   z-index: 1;
}

.parallax1 {
   background-color: gray;
   text-align: center;
   height: 500px;
}
</style>

Here, I should mention that you can change this code and that it does not relate to the actual movement.

Now, to the real part – jQuery coda that will latch on the scroll event and calculate the position of the bar on the page. This code, obviously, replaces the <script></script> line:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">

   var parallaxElements = [];
   var windowHeight = 0;

   $(document).ready(function () {
      windowHeight = $(window).height();

      // touch event check borrowed from Modernizr
      var touchSupported = (('ontouchstart' in window) ||
                           window.DocumentTouch && document instanceof DocumentTouch);

      // if touch events are supported, tie our animation to the position to these events as well
      if (touchSupported) {
         $(window).bind('touchmove', function (e) {
            var val = e.currentTarget.scrollY;
            parallax(val);
         });
      }

      $(window).bind('scroll', function (e) {
         var val = $(this).scrollTop();
         parallax(val);
      });

      // update vars used in parallax calculations on window resize
      $(window).resize(function () {
         windowHeight = $(this).height();

         for (var id in parallaxElements) {
            parallaxElements[id].initialOffsetY = $(parallaxElements[id].elm).offset().top;
            parallaxElements[id].height = $(parallaxElements[id].elm).height();
         }
      });

      // get parallax elements straight away as they wont change
      // this will minimise DOM interactions on scroll events
      $('.parallax').each(function () {
         $elm = $(this);
         var id = $elm.data('id');

         // use data-id as key
         parallaxElements[id] = {
            id: $elm.data('id'),
            start: $elm.data('start'),
            stop: $elm.data('stop'),
            elm: $elm[0],
            initialOffsetY: $elm.offset().top,
            height: $elm.height(),
            width: $elm.outerWidth()
         };

      });
   });

   function parallax(scrollTop) {
      for (var id in parallaxElements) {
         // distance of element from top of viewport
         var viewportOffsetTop = parallaxElements[id].initialOffsetY - scrollTop;

         // distance of element from bottom of viewport
         var viewportOffsetBottom = windowHeight - viewportOffsetTop;
         if ((viewportOffsetBottom >= parallaxElements[id].start) &&
                    (viewportOffsetBottom <= parallaxElements[id].stop)) {
            // element is now active, fix the position so when we scroll it stays fixed

            var pos = (windowHeight - parallaxElements[id].start);
            $(parallaxElements[id].elm).css({
                        position: 'fixed',
                        top: pos + 'px',
                        left: '50%',
                        marginLeft: -(parallaxElements[id].width / 2) + 'px'
            });

         } else if (viewportOffsetBottom > parallaxElements[id].stop) {
            // scrolled past the stop value, make position relative again
            $(parallaxElements[id].elm).css({
                        position: 'relative',
                        top: (parallaxElements[id].stop - parallaxElements[id].start) + 'px',
                        left: 'auto',
                        marginLeft: 'auto'
            });

         } else if (viewportOffsetBottom < parallaxElements[id].start) {
            // scrolled up back past the start value, reset position
            $(parallaxElements[id].elm).css({
                        position: 'relative',
                        top: 0,
                        left: 'auto',
                        marginLeft: 'auto'
            });

         }
      }
   }
</script>

I already said it’s a lot of code. The good news is that you can mark any element with the class parallax and it will be added to the array for movement. The settings for each of these elements – when to start the effect and when to stop it – are defined for each one with data-start and data-stop attributes. One more important thing is the data-id, which should be unique when you have more than one element decorated with the parallax class.

You can check out my demo here. I will expand the demo to add different speeds when scrolling so bookmark my blog and check soon.

Related articles

How to Rotate an Element with jQuery and CSS When Scrolling a Page or see  the demo here.