Parallax slider (JS animations)

by Eric Hynds

HTML

<div id="buttons">
    <button id="prev">Prev</button>
    <button id="next">Next</button>
</div>

<ul id="pages"></ul>

<div id="hero-container">
    <div class="hero-image" style="background-image: url(http://placeimg.com/640/480/any?1)">
        <div class="hero-text">
            <div>HERO 1</div>
            <div>More info on Hero 1.</div>
        </div>
    </div>
    <div class="hero-image" style="background-image: url(http://placeimg.com/640/480/any?2)">
        <div class="hero-text">
            <div>HERO 2</div>
            <div>More info on Hero 2.</div>
        </div>
    </div>
    <div class="hero-image" style="background-image: url(http://placeimg.com/640/480/any?3)">
        <div class="hero-text">
            <div>HERO 3</div>
            <div>More info on Hero 3.</div>
        </div>
    </div>
</div>

CSS

html, body {
    width: 100%;
    height: 100%;
    margin: 0;
}

#buttons {
    position: absolute;
    z-index: 20;
    top: 20px;
    left: 20px;
}
#pages {
    position: absolute;
    z-index: 20;
    top: 25px;
    left: 120px;
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
}
#pages li {
    float: left;
    margin: 0 5px;
    color: #fff;
    border: 1px solid #fff;
    width: 8px;
    height: 8px;
    display: block;
}
#pages li.is-active {
    background: #fff;
}
.hero-image:first-child {
    display: block;
    z-index: 5;
}
.hero-image.in-slide {
    top: 100%;
    display: block;
    z-index: 10;
}
.hero-image.in-slide .hero-text {
    top: 200%;
}
.reverse .hero-image.in-slide {
    top: -100%;
}
.reverse .hero-image.in-slide .hero-text {
    top: -200%;
}
#hero-container {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
.hero-image {
    background-color: #000;
    background-size: cover;
    background-position: center;
    width: 100%;
    height: 100%;
    position: absolute;
}
.hero-text {
    position: absolute;
    left: 10%;
    top: 70%;
    color: #FFF;
    font-family: sans-serif;
    font-size: 30px;
    text-shadow: 0px 0px 8px black, 0px 0px 2px black;
}

JavaScript

(function() {
  function Parallax(elem, opts) {
    this.opts = $.extend(Parallax.defaults, opts || {});
    this.$container = $(elem);
    this.$slides = this.$container.children();
    this.$text = this.$slides.find('.hero-text');

    this.$slides.each(function(index) {
      $.data(this, 'index', index);
    });

    this._initPagination();
    this._startTimer();
  }

  Parallax.prototype._initPagination = function() {
    if(!this.opts.pages) return;
    var $pages = this.opts.pages;
    var activeClass = this.opts.activeClass;

    $pages.html(function() {
      return this.$slides.map(function(index) {
        return '<li class="' + (index ? '' : activeClass) + '"></li>';
      }).get().join('');
    }.bind(this));

    this.$container.on('parallax:moved', function(event, data) {
      var $lis = $pages.children();
      $lis.removeClass(activeClass);
      $lis.eq(data.$in.data('index')).addClass(activeClass);
    }.bind(this));
  };

  Parallax.prototype._startTimer = function() {
    if(!this.opts.autoscroll) return;
    clearTimeout(this.timer);
    this.timer = setTimeout(this.next.bind(this), this.opts.autoscroll);
  };

  Parallax.prototype._done = function(dir, $in, $out) {
    if(dir === 'next') {
      this.$container.append($out);
    } else {
      this.$container.prepend($in);
    }

    this.isTransitioning = false;
    this.$container.removeClass('reverse');
    this.$slides.removeClass('in-slide out-slide');
    this.$slides.css('top', '');
    this.$text.css('top', '');
    this.$container.trigger('parallax:moved', { $in: $in, $out: $out });
    this._startTimer();
  };

  Parallax.prototype.move = function(dir) {
    if(this.isTransitioning) return;
    this.isTransitioning = true;
    var isNext = dir === 'next';
    this.$container.addClass(isNext ? '' : 'reverse');
    var $slides = this.$container.children();
    var $in = $slides.eq(isNext ? 1 : -1);
    var $out = $slides.eq(0);
    var $inText = $in.find('.hero-text');
    var...