Skip to content

Instantly share code, notes, and snippets.

@abernier
Last active October 13, 2020 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abernier/0837661e346360b5385b to your computer and use it in GitHub Desktop.
Save abernier/0837661e346360b5385b to your computer and use it in GitHub Desktop.
//ax
node_modules/

DEPRECATED: use @abernier/parallax instead

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/7f928620dbe65570950ab551ee06b82e480507bb/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/7f928620dbe65570950ab551ee06b82e480507bb.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
Copy link
Author

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