<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<script type="text/javascript" src="//use.typekit.net/rws3een.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<div class="container">
<div class="container-inner">
<div class="background"></div>
<section id="intro" class="wrapper">
<h1 class="name">Parallax Demo</h1>
<h2 class="byline">An experiment by Dave Gamache</h2>
</section>
<section id="explosion" class="wrapper">
<p class="explosion-byline">Here's an example of 16 elements scaling, fading and moving at once.</p>
<ul id="domExplosionList">
<li class="dom-explosion-item dei-1"></li>
<li class="dom-explosion-item dei-2"></li>
<li class="dom-explosion-item dei-3"></li>
<li class="dom-explosion-item dei-4"></li>
<li class="dom-explosion-item dei-5"></li>
<li class="dom-explosion-item dei-6"></li>
<li class="dom-explosion-item dei-7"></li>
<li class="dom-explosion-item dei-8"></li>
<li class="dom-explosion-item dei-9"></li>
<li class="dom-explosion-item dei-10"></li>
<li class="dom-explosion-item dei-11"></li>
<li class="dom-explosion-item dei-12"></li>
<li class="dom-explosion-item dei-13"></li>
<li class="dom-explosion-item dei-14"></li>
<li class="dom-explosion-item dei-15"></li>
<li class="dom-explosion-item dei-16"></li>
</ul>
</section>
<section id="images" class="wrapper">
<p class="images-byline">Or better yet, a realistic example of showcasing some design work.</p>
<p class="images-byline-2">Really, anything is possible …</p>
<img id="mediumHomepage" class="raw-page" src="https://goo.gl/xRsl79">
<div class="iphone">
<img class="iphone-frame" src="https://goo.gl/1rjtLX">
<div class="iphone-viewport">
<img id="medium-profile-iphone" class="iphone-content" src="https://goo.gl/jFK9oy">
<img id="davegamache-dot-com" class="iphone-content" src="https://goo.gl/nkqE1t">
</div>
</div>
</section>
<section id="links">
<p class="links-byline">Learn how to make your parallax site smooth like this one.</p>
<a class="btn" href="#">Read about it on Medium</a>
</section>
</div>
</div>
<h3 class="error">Whoops! Right now this demo doesn't handle resizing or browsers less than 1000px wide. Reload this page or get on a laptop!</h3>
<script>
(function() {
$(function() {
/* Globals
-------------------------------------------------- */
var PROPERTIES = ['translateX', 'translateY', 'opacity', 'rotate', 'scale'],
$window = $(window),
$body = $('body'),
wrappers = [],
currentWrapper = null,
scrollTimeoutID = 0,
bodyHeight = 0,
windowHeight = 0,
windowWidth = 0,
prevKeyframesDurations = 0,
scrollTop = 0,
relativeScrollTop = 0,
currentKeyframe = 0,
keyframes = [
{
'wrapper' : '#intro',
'duration' : '100%',
'animations' : [
{
'selector' : '.name',
'translateY' : -140,
'opacity' : 0
} , {
'selector' : '.byline',
'translateY' : -110,
'opacity' : 0
} , {
'selector' : '.twitter',
'opacity' : [1, 0]
}
]
} , {
'wrapper' : '#explosion',
'duration' : '150%',
'animations' : [
{
'selector' : '.explosion-byline',
'translateY' : '-25%',
'opacity' : [0, 1.75] // hack to accelrate opacity speed
} , {
'selector' : '#domExplosionList',
'translateY' : '-70%',
'opacity' : [0, 1] // hack to accelrate opacity speed
}
]
} , {
'wrapper' : '#explosion',
'duration' : '150%',
'animations' : [
{
'selector' : '.dei-1',
'translateY' : '-15%',
'translateX' : '-10%',
'opacity' : [1, 0],
'scale' : 2,
} , {
'selector' : '.dei-2',
'translateY' : '-5%',
'translateX' : '-4%',
'opacity' : [1, 0] // hack to decelrate opacity speed
} , {
'selector' : '.dei-3',
'translateY' : '-9%',
'translateX' : '2%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.2,
} , {
'selector' : '.dei-4',
'translateY' : '-17%',
'translateX' : '8%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.5,
} , {
'selector' : '.dei-5',
'translateY' : '-2%',
'translateX' : '-15%',
'opacity' : [1, 0],
'scale' : 2,
} , {
'selector' : '.dei-6',
'translateY' : '-1%',
'translateX' : '-7%',
'opacity' : [1, 0], // hack to decelrate opacity speed
'scale' : 1.2,
} , {
'selector' : '.dei-7',
'translateY' : '-4%',
'translateX' : '2%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.1,
} , {
'selector' : '.dei-8',
'translateY' : '-3%',
'translateX' : '12%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.8,
} , {
'selector' : '.dei-9',
'translateY' : '3%',
'translateX' : '-12%',
'opacity' : [1, 0],
'scale' : 1.5,
} , {
'selector' : '.dei-10',
'translateY' : '5%',
'translateX' : '-4%',
'opacity' : [1, 0] // hack to decelrate opacity speed
} , {
'selector' : '.dei-11',
'translateY' : '8%',
'translateX' : '6%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.4,
} , {
'selector' : '.dei-12',
'translateY' : '1%',
'translateX' : '20%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.9,
} , {
'selector' : '.dei-13',
'translateY' : '8%',
'translateX' : '-12%',
'opacity' : [1, 0],
'scale' : 1.8,
} , {
'selector' : '.dei-14',
'translateY' : '4%',
'translateX' : '-3%',
'opacity' : [1, 0], // hack to decelrate opacity speed
'scale' : 1.3,
} , {
'selector' : '.dei-15',
'translateY' : '14%',
'translateX' : '5%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 1.7,
} , {
'selector' : '.dei-16',
'translateY' : '6%',
'translateX' : '9%',
'opacity' : [1, 0], // hack to accelrate opacity speed
'scale' : 2,
}
]
} , {
'wrapper' : '#explosion',
'duration' : '100%',
'animations' : [
{
'selector' : '.explosion-byline',
'translateY' : ['-25%', '-40%'],
'opacity' : [1, 0] // hack to accelrate opacity speed
}
]
} , {
'wrapper' : '#images',
'duration' : '150%',
'animations' : [
{
'selector' : '.images-byline',
'translateY' : '-25%',
'opacity' : [0, 1.75] // hack to accelrate opacity speed
} , {
'selector' : '#mediumHomepage',
'translateY' : '-90%'
} , {
'selector' : '.iphone',
'translateY' : '-66%'
}
]
} , {
'wrapper' : '#images',
'duration' : '75%',
'animations' : []
} , {
'wrapper' : '#images',
'duration' : '150%',
'animations' : [
{
'selector' : '.images-byline',
'translateY' : ['-25%', '-25%'],
'scale' : .7,
'opacity' : [1.75, -.75] // hack to accelrate opacity speed
} , {
'selector' : '.images-byline-2',
'opacity' : [0, 1],
'translateY' : '-15%'
} , {
'selector' : '#mediumHomepage',
'translateY' : ['-90%', '-90%'],
'scale' : .8,
'opacity' : -.75
} , {
'selector' : '.iphone',
'translateY' : ['-66%', '-90%'],
'translateX' : '-2%',
'rotate' : -90,
'scale' : 1.3
} , {
'selector' : '#medium-profile-iphone',
'scale' : .9,
'translateX' : '20%',
} , {
'selector' : '#davegamache-dot-com',
'scale' : [.5, 1]
}
]
} , {
'wrapper' : '#images',
'duration' : '40%',
'animations' : []
} , {
'wrapper' : '#images',
'duration' : '150%',
'animations' : [
{
'selector' : '.images-byline-2',
'opacity' : [1, .5],
'translateY' : ['-15%', '50%'],
'opacity' : [1, -2]
} , {
'selector' : '.iphone',
'translateY' : ['-90%', '5%'],
'translateX' : ['-2%', '-2%'],
'rotate' : [-90, -90],
'scale' : [1.3, 1.3]
} , {
'selector' : '#medium-profile-iphone',
'translateX' : ['20%', '20%']
} , {
'selector' : '#davegamache-dot-com',
'scale' : [1, 1]
}
]
} , {
'wrapper' : '#links',
'duration' : '100%',
'animations' : [
{
'selector' : '#links',
'opacity' : [0, 2],
'scale' : [.8, 1]
} , {
'selector' : '.twitter',
'opacity' : [0, 1]
}
]
} , {
'duration' : '100%',
'animations' : []
}
]
/* Construction
-------------------------------------------------- */
init = function() {
scrollIntervalID = setInterval(updatePage, 10);
setupValues();
$window.resize(throwError)
if(isTouchDevice) {
$window.resize(throwError)
}
}
setupValues = function() {
scrollTop = $window.scrollTop();
windowHeight = $window.height();
windowWidth = $window.width();
convertAllPropsToPx();
buildPage();
}
buildPage = function() {
var i, j, k;
for(i=0;i<keyframes.length;i++) { // loop keyframes
bodyHeight += keyframes[i].duration;
if($.inArray(keyframes[i].wrapper, wrappers) == -1) {
wrappers.push(keyframes[i].wrapper);
}
for(j=0;j<keyframes[i].animations.length;j++) { // loop animations
Object.keys(keyframes[i].animations[j]).forEach(function(key) { // loop properties
value = keyframes[i].animations[j][key];
if(key !== 'selector' && value instanceof Array === false) {
var valueSet = [];
valueSet.push(getDefaultPropertyValue(key), value);
value = valueSet;
}
keyframes[i].animations[j][key] = value;
});
}
}
$body.height(bodyHeight);
$window.scroll(0);
currentWrapper = wrappers[0];
$(currentWrapper).show();
}
convertAllPropsToPx = function() {
var i, j, k;
for(i=0;i<keyframes.length;i++) { // loop keyframes
keyframes[i].duration = convertPercentToPx(keyframes[i].duration, 'y');
for(j=0;j<keyframes[i].animations.length;j++) { // loop animations
Object.keys(keyframes[i].animations[j]).forEach(function(key) { // loop properties
value = keyframes[i].animations[j][key];
if(key !== 'selector') {
if(value instanceof Array) { // if its an array
for(k=0;k<value.length;k++) { // if value in array is %
if(typeof value[k] === "string") {
if(key === 'translateY') {
value[k] = convertPercentToPx(value[k], 'y');
} else {
value[k] = convertPercentToPx(value[k], 'x');
}
}
}
} else {
if(typeof value === "string") { // if single value is a %
if(key === 'translateY') {
value = convertPercentToPx(value, 'y');
} else {
value = convertPercentToPx(value, 'x');
}
}
}
keyframes[i].animations[j][key] = value;
}
});
}
}
}
getDefaultPropertyValue = function(property) {
switch (property) {
case 'translateX':
return 0;
case 'translateY':
return 0;
case 'scale':
return 1;
case 'rotate':
return 0;
case 'opacity':
return 1;
default:
return null;
}
}
/* Animation/Scrolling
-------------------------------------------------- */
updatePage = function() {
window.requestAnimationFrame(function() {
setScrollTops();
if(scrollTop > 0 && scrollTop <= (bodyHeight - windowHeight)) {
animateElements();
setKeyframe();
}
});
}
setScrollTops = function() {
scrollTop = $window.scrollTop();
relativeScrollTop = scrollTop - prevKeyframesDurations;
}
animateElements = function() {
var animation, translateY, translateX, scale, rotate, opacity;
for(var i=0;i<keyframes[currentKeyframe].animations.length;i++) {
animation = keyframes[currentKeyframe].animations[i];
translateY = calcPropValue(animation, 'translateY');
translateX = calcPropValue(animation, 'translateX');
scale = calcPropValue(animation, 'scale');
rotate = calcPropValue(animation, 'rotate');
opacity = calcPropValue(animation, 'opacity');
$(animation.selector).css({
'transform': 'translate3d(' + translateX +'px, ' + translateY + 'px, 0) scale('+ scale +') rotate('+ rotate +'deg)',
'opacity' : opacity
})
}
}
calcPropValue = function(animation, property) {
var value = animation[property];
if(value) {
value = easeInOutQuad(relativeScrollTop, value[0], (value[1]-value[0]), keyframes[currentKeyframe].duration);
} else {
value = getDefaultPropertyValue(property);
}
// value = +value.toFixed(2)
// TEMPORARILY REMOVED CAUSE SCALE DOESN'T WORK WITHA AGRESSIVE ROUNDING LIKE THIS
return value;
}
easeInOutQuad = function (t, b, c, d) {
//sinusoadial in and out
return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
};
setKeyframe = function() {
if(scrollTop > (keyframes[currentKeyframe].duration + prevKeyframesDurations)) {
prevKeyframesDurations += keyframes[currentKeyframe].duration;
currentKeyframe++;
showCurrentWrappers();
} else if(scrollTop < prevKeyframesDurations) {
currentKeyframe--;
prevKeyframesDurations -= keyframes[currentKeyframe].duration;
showCurrentWrappers();
}
}
showCurrentWrappers = function() {
var i;
if(keyframes[currentKeyframe].wrapper != currentWrapper) {
$(currentWrapper).hide();
$(keyframes[currentKeyframe].wrapper).show();
currentWrapper = keyframes[currentKeyframe].wrapper;
}
}
/* Helpers
-------------------------------------------------- */
convertPercentToPx = function(value, axis) {
if(typeof value === "string" && value.match(/%/g)) {
if(axis === 'y') value = (parseFloat(value) / 100) * windowHeight;
if(axis === 'x') value = (parseFloat(value) / 100) * windowWidth;
}
return value;
}
throwError = function() {
$body.addClass('page-error')
}
isTouchDevice = function() {
return 'ontouchstart' in window // works on most browsers
|| 'onmsgesturechange' in window; // works on ie10
}
init();
})
}).call(this);
</script>
/* #Reset & Basics (Inspired by E. Meyers)
================================================== */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block; }
body { line-height: 1; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none; }
table {
border-collapse: collapse;
border-spacing: 0; }
/* #Basic Styles
================================================== */
body {
background: #fff;
font: 24px/1.6 "brandon-grotesque", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #fff;
-webkit-font-smoothing: antialiased; /* Fix for webkit rendering */
-webkit-text-size-adjust: 100%;
}
/* #Typography
================================================== */
h1, h2, h3, h4, h5, h6 { font-weight: bold;}
h1 { font-size: 60px; line-height: 1.1; }
h2 { font-size: 48px; line-height: 1.2; }
h3 { font-size: 36px; line-height: 1.3; }
h4 { font-size: 24px; line-height: 1.4; }
h5 { font-size: 21px; line-height: 1.5; }
h6 { font-size: 18px; line-height: 1.6; }
p { margin: 0 0 20px 0; }
em { font-style: italic; }
strong { font-weight: bold; }
hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; }
/* #Links
================================================== */
a { color: #333; text-decoration: underline; outline: 0; }
a:hover, a:focus { color: #000; }
p a, p a:visited { line-height: inherit; }
body {
background: #111;
font-weight: 300;
}
.background {
position: fixed;
width: 100%;
height: 100%;
background-image: url('https://goo.gl/LM6hUJ');
background-size: cover;
background-position: center;
text-rendering: optimizeLegibility;
}
.background:after {
content: '';
position: fixed;
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
border: 0;
}
.wrapper {
display: none;
}
/* 1. Intro Keyframe
--------------------------------------- */
#intro {
position: fixed;
top: 48%;
left: 10%;
width: 80%;
color: #fff;
text-align: center;
text-transform: uppercase;
}
.name {
font-size: 35px;
letter-spacing: 12px;
line-height: 1.5;
font-weight: 900;
}
.byline {
font-size: 15px;
letter-spacing: 4px;
text-align: center;
font-weight: 300;
}
.ampersand {
font-family: "Adobe Caslon Pro", "brandon-grotesque";
font-style: italic;
}
/* 2. Explosion/Images/Links Structure and Text
--------------------------------------- */
#explosion,
#images {
position: fixed;
top: 100%;
width: 100%;
height: 100%;
}
.explosion-byline,
.images-byline {
position: fixed;
top: 63%;
left: 10%;
color: white;
max-width: 22%;
opacity: 0;
}
.images-byline-2 {
text-align: center;
position: fixed;
top: 93%;
left: 25%;
color: white;
width: 50%;
opacity: 0;
}
/* 3. Explosion Keyframe
--------------------------------------- */
#domExplosionList {
position: fixed;
width: 270px;
top: 100%;
right: 15%;
opacity: 0;
}
.dom-explosion-item {
position: absolute;
width: 60px;
height: 60px;
background-color: #fff;
}
.dei-1 { top: 0; left: 0; }
.dei-2 { top: 0; left: 70px; }
.dei-3 { top: 0; left: 140px; }
.dei-4 { top: 0; left: 210px; }
.dei-5 { top: 70px; left: 0; }
.dei-6 { top: 70px; left: 70px; }
.dei-7 { top: 70px; left: 140px; }
.dei-8 { top: 70px; left: 210px; }
.dei-9 { top: 140px; left: 0; }
.dei-10 { top: 140px; left: 70px; }
.dei-11 { top: 140px; left: 140px; }
.dei-12 { top: 140px; left: 210px; }
.dei-13 { top: 210px; left: 0; }
.dei-14 { top: 210px; left: 70px; }
.dei-15 { top: 210px; left: 140px; }
.dei-16 { top: 210px; left: 210px; }
/* 3. Images Keyframe
--------------------------------------- */
.raw-page {
position: fixed;
width: 45%;
border-radius: 6px;
box-shadow: inset 0 0 1px rgba(255,255,255,.3);
border: 1px solid rgba(0,0,0,.2);
background-clip: padding-box;
}
#mediumHomepage {
top: 100%;
right: 5%;
}
.iphone {
position: fixed;
right: 40%;
top: 102%;
width: 16%;
}
.iphone-frame {
position: relative;
width: 100%;
height: auto;
background-size: 100%;
z-index: 2;
}
.iphone-viewport {
width: 83.5%;
height: 69.5%;
position: absolute;
top: 14%;
left: 8%;
overflow: hidden;
background-color: #000;
}
.iphone-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
#medium-profile-iphone {
z-index: 2;
}
/* 3. Links Keyframe
--------------------------------------- */
#links {
position: fixed;
top: 48%;
left: 10%;
width: 80%;
color: #fff;
text-align: center;
opacity: 0;
}
.links-byline {
font-size: 30px;
line-height: 1.15;
}
.btn {
display: inline-block;
padding: 10px 20px;
border: 1px solid rgba(255,255,255,.5);
color: rgba(255,255,255,.8);
font-size: 12px;
font-weight: 900;
text-decoration: none;
border-radius: 50px;
text-align: center;
text-transform: uppercase;
letter-spacing: .1em;
}
.btn:hover,
.btn:focus {
color: #fff;
border-color: #fff;
}
.twitter {
position: fixed;
top: 20px;
right: 20px;
}
/* 4. Handling resize and small devices
--------------------------------------- */
.error {
display: none;
position: fixed;
width: 80%;
font-size: 30px;
font-weight: 300;
text-align: center;
top: 30%;
left: 10%;
}
.page-error .error {
*display: block;
}
.page-error .container {
*display: none;
}
@media all and (max-width: 1000px) {
.container {
*display: none;
}
.error {
*display: block;
font-size: 22px;
}
}