JSFiddle - React, Tailwind, and code Playground
by joecritch
HTML
<div class="container">
<section class="top">
<div class="shards">
<span data-props='{"x": 58, "y": 1500, "inertia": 0.2}'></span>
<span data-props='{"x": 372, "y": 1500, "inertia": 0.6}'></span>
<span data-props='{"x": 986, "y": 1500, "inertia": 0.8}'></span>
</div>
</section>
<section class="portfolio">
<div class="shards">
<span data-props='{"x": 58, "y": 1500, "inertia": 0.2}'></span>
<span data-props='{"x": 372, "y": 1500, "inertia": 0.6}'></span>
<span data-props='{"x": 986, "y": 1500, "inertia": 0.8}'></span>
</div>
</section>
<section class="about">
<div class="shards">
<span data-props='{"x": 58, "y": 1500, "inertia": 0.2}'></span>
<span data-props='{"x": 372, "y": 1500, "inertia": 0.6}'></span>
<span data-props='{"x": 986, "y": 1500, "inertia": 0.8}'></span>
</div>
</section>
</div>
CSS
.container {
width: 1700px;
overflow: hidden;
}
section {
min-height: 600px;
background: yellow;
position: relative;
z-index: 3;
}
section.top {
background: yellow;
}
section.portfolio {
background: cyan;}
section.about {
background: lime;}
.shards {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.shards > span {
position: absolute;
display: block;
width: 600px; /* Bigger than necessary, to save manually entering widths and heights */
height: 500px;
background: none no-repeat 0 0;
}
section.top .shards > span { background-image: url('http://f.cl.ly/items/0y012M032H0h151I2K1T/home-1.png'); }
section.top .shards > span + span { background-image: url('http://f.cl.ly/items/0H192d3h2V2d262D250M/home-2.png'); }
section.top .shards > span + span + span { background-image: url('http://f.cl.ly/items/0q3I3x140b1x1Z3l2o0w/home-3.png'); }
section.portfolio .shards > span { background-image: url('http://f.cl.ly/items/0v2d062h1H2d371s1M1z/portfolio-1.png'); }
section.portfolio .shards > span + span { background-image: url('http://f.cl.ly/items/1y1y1E3d1C3S3q2h2Q0N/portfolio-2.png'); }
section.portfolio .shards > span + span + span { background-image: url('http://f.cl.ly/items/0d1O0Z0m3S2T3Q3t0l2v/portfolio-3.png'); }
section.about .shards > span { background-image: url('http://f.cl.ly/items/0y012M032H0h151I2K1T/home-1.png'); }
section.about .shards > span + span { background-image: url('http://f.cl.ly/items/0H192d3h2V2d262D250M/home-2.png'); }
section.about .shards > span + span + span { background-image: url('http://f.cl.ly/items/0q3I3x140b1x1Z3l2o0w/home-3.png'); }
JavaScript
// Track visibility
$.fn.trackVisibility = function(options) {
var defaults = {
aboveClass: 'above',
belowClass: 'below',
visibleClass: 'visible'
};
var config = $.extend({}, defaults, options);
var $window = $(window);
return this.each(function() {
var $this = $(this);
var height = $this.height();
var offset = $this.offset().top;
var refresh = function(e) {
var windowPos = $window.scrollTop();
if ((height + offset) < windowPos) {
$this.addClass(config.aboveClass).removeClass(config.visibleClass);
}
else if (offset > windowPos + window.innerHeight) {
$this.addClass(config.belowClass).removeClass(config.visibleClass);
}
else {
$this.removeClass(config.aboveClass + ' ' + config.belowClass).addClass(config.visibleClass);
}
};
$(window).bind('scroll resize', refresh);
});
};
// Track backgrounds (parallax w/ inertia)
$.fn.trackBackgrounds = function(options) {
var defaults = {
minHeight: 600,
visibleClass: 'visible'
};
var config = $.extend({}, defaults, options);
var $window = $(window);
return this.each(function() {
var $this = $(this);
// var $shards = $(this).find('.shards');
//console.log($shards);
var moveBackground = function() {
var windowPos = $window.scrollTop();
if ($this.hasClass('visible')) {
var positions = [];
var $shards = $this.data('shards');
$shards.each(function() {
var $span = $(this);
var props = $span.data('props');
var inertia = (props.inertia === 0) ? 1 : props.inertia;
var pos = {
x: props.x,
y: ~~ (-((config.minHeight + windowPos) - props.y) *...