Instantly share code, notes, and snippets.

@abernier /.gitignore
Last active Jul 30, 2018

Embed
What would you like to do?
//ax
node_modules/

Hardware-accelerated parallax

Demo: http://bl.ocks.org/abernier/raw/0837661e346360b5385b/

INSTALL

browser-side

<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script src="https://cdn.rawgit.com/abernier/3225993/raw/427b4179e228f79a7f49f8981f3a1d233deb73b7/loop.js"></script>
<script src="parallax.js"></script>

Server-side

npm install https://gist.github.com/abernier/0837661e346360b5385b/archive/847d8c07b85c0532d7a3931f90d522587cd50b85.tar.gz

Usage

$('#my').parallax({amplitude: .5});

or

var el = document.getElementById('my');

var parallax = new Parallax(el, {
  amplitude: .5 // default: 1
});
parallax.loop.start();
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1,initial-scale=1,user-scalable=no">
<style>
p {text-align:center;}
.strong {position:relative;z-index:1; font-size:200%;}
.my {
height:500px; margin:200% 0;
outline:100em solid rgba(255,255,255,.8); box-shadow:inset 0 0 0px 2px red;
background:url(http://lorempixel.com/1400/1900/) center no-repeat; background-size:cover;
overflow:visible!important;
}
.my >div {
position:relative;z-index:-1;
}
.my p {font-size:500%;}
</style>
</head>
<body>
<p class="strong">Scroll down<br>↓↓↓</p>
<p><a href="https://gist.github.com/abernier/0837661e346360b5385b#file-readme-md">README</a>
<div class="my">
<p>Lorem ipsum</p>
</div>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script src="https://rawgit.com/abernier/3225993/raw/7f928620dbe65570950ab551ee06b82e480507bb/loop.js"></script>
<script src="parallax.js"></script>
<script>
$('.my').parallax({amplitude: 1});
</script>
</body>
</html>
{
"name": "parallax",
"version": "0.1.1",
"description": "",
"main": "parallax.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gist.github.com/0837661e346360b5385b.git"
},
"author": "Antoine BERNIER",
"license": "ISC",
"dependencies": {
"jquery": "^2.1.1",
"loop": "https://gist.github.com/abernier/3225993/archive/427b4179e228f79a7f49f8981f3a1d233deb73b7.tar.gz"
}
}
(function () {
var $ = this.jQuery || require('jquery');
var _ = this._ || require('underscore');
var $html = $('html');
var $window = $(window);
var TRANSFORMPROP = ["transform", "webkitTransform", "MozTransform", "msTransform"].filter(function (prop) {
return prop in document.documentElement.style;
})[0];
//
// https://www.html5rocks.com/en/tutorials/speed/animations/?redirect_from_locale=fr#debouncing-scroll-events
//
var lastScrollY = window.pageYOffset;
function onScroll() {
requestTick();
lastScrollY = window.pageYOffset;
}
var ticking = false;
function requestTick() {
if (!ticking) {
ticking = true;
requestAnimationFrame(update);
}
}
function update() {
var l = instances.length;
var instance;
while (l--) {
instance = instances[l];
var percent = instance.percent(lastScrollY);
instance.draw(percent);
}
// allow further rAFs to be called
ticking = false;
}
window.addEventListener('scroll', onScroll, false);
//
//
//
var instances = [];
function Parallax(el, options) {
options || (options = {});
this.constructor.insertStyle();
this.$el = $(el);
this.el = this.$el[0];
this.amplitude = options.amplitude || 1;
// Add .parallax class
this.el.classList.add('parallax');
if (this.$el.css('position') === 'static') {
this.$el.css('position', 'relative');
}
// Insert pseudo .img div
this.$img = $('<div class="img"/>').css({
'background-image': this.$el.css('background-image'),
'height': (100*(1+this.amplitude) + '%')
}).prependTo(this.$el);
this.$el.css('background-image', 'none');
//
// setDims + resize
//
$window.on('resize', _.debounce(this.setDims.bind(this), 200));
this.$img.on('webkitTransitionEnd mozTransitionEnd oTransitionEnd msTransitionEnd transitionend', _.debounce(function (e) {
//console.log('transitionend', e.target);
if (!(e.originalEvent.target === this.$img[0] && e.originalEvent.propertyName === 'height')) {
return;
}
e.originalEvent.stopPropagation();
this.setDims();
}.bind(this), 30));
this.setDims();
//
// initial draw
//
var percent = this.percent(lastScrollY);
this.draw(percent);
instances.push(this);
}
Parallax.prototype.setDims = function () {
//console.log('setDims');
this.offsettop = this.$el.offset().top,
this.WH = $(window).height(),
this.h = this.$el.outerHeight();
this.hh = this.$img.height();
this.minoffsettop = this.offsettop - this.WH;
this.maxoffsettop = this.offsettop + this.h;
};
Parallax.prototype.percent = function (scrolltop) {
var percent = ((this.offsettop - scrolltop) + this.h) / (this.WH + this.h);
return percent;
};
Parallax.prototype.draw = function (percent) {
//console.log(percent);
var pmin = .5-this.amplitude/2;
var pmax = .5+this.amplitude/2;
percent = percent * (pmax - pmin) + pmin;
var ty = Math.round(-percent*this.hh + (1-percent)*this.h);
if (ty === this._ty) return;
this._ty = ty;
var t;
if (Parallax.has3d) {
t = 'translate3d(0,' + ty + 'px,0)';
} else {
t = 'translate(0,' + ty + 'px)';
}
//console.log(ty);
if (percent > 0 && percent < 1) {
//this.$img.css('transform', t);
this.$img[0].style[TRANSFORMPROP] = t;
}
};
// http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support#answer-12621264
function has3d() {
var el = document.createElement('p');
var has3d;
var transforms = {
'webkitTransform':'-webkit-transform',
'OTransform':'-o-transform',
'msTransform':'-ms-transform',
'MozTransform':'-moz-transform',
'transform':'transform'
};
// Add it to the body to get the computed style.
document.body.insertBefore(el, null);
for (var t in transforms) {
if (el.style[t] !== undefined) {
el.style[t] = "translate3d(1px,1px,1px)";
has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
}
}
document.body.removeChild(el);
return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
}
Parallax.has3d = has3d();
Parallax.css = ''
+ '.parallax {overflow:hidden;}'
+ '.parallax >.img {'
+ ' display:block;width:100%; background-position:center;background-repeat:no-repeat; -webkit-background-size:cover;-moz-background-size:cover;background-size:cover;'
+ ' position:absolute;left:0;top:0;'
+ ' -webkit-transition:height 1ms;-moz-transition:height 1ms;-o-transition:height 1ms;-ms-transition:height 1ms;transition:height 1ms;'
+ ' will-change:transform;'
+ '}'
;
Parallax.insertStyle = function () {
if (this.$style) return; //once
if (!this.$style) {
this.$style = $('<style/>').text(this.css).appendTo(document.head);
}
};
//
// jQuery plugin
//
$.fn.parallax = function (options) {
this.each(function (i, el) {
var $el = $(el);
var parallax = new Parallax(el, options);
$el.data('parallax', parallax);
});
}
//
// CommonJS
//
this.Parallax = Parallax;
if (typeof module !== "undefined" && module !== null) {
module.exports = this.Parallax;
}
}).call(this);
@abernier

This comment has been minimized.

Show comment
Hide comment
Owner

abernier commented Aug 13, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment