<body data-hijacking="off" data-animation="opacity">
<section class="cd-section visible">
<div>
<h2>Page Scroll Effects</h2>
</div>
</section>
<section class="cd-section">
<div>
<h2>Section 2</h2>
</div>
</section>
<section class="cd-section">
<div>
<h2>Section 3</h2>
</div>
</section>
<section class="cd-section">
<div>
<h2>Section 4</h2>
</div>
</section>
<section class="cd-section">
<div>
<h2>Section 5</h2>
</div>
</section>
<nav>
<ul class="cd-vertical-nav">
<li><a href="#0" class="cd-prev inactive">Next</a></li>
<li><a href="#0" class="cd-next">Prev</a></li>
</ul>
</nav> <!-- .cd-vertical-nav -->
</body>
/* --------------------------------
Primary style
-------------------------------- */
*, *::after, *::before {
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
font-size: 1.6rem;
font-family: "Open Sans", sans-serif;
color: lightcoral;
font-weight:700;
background-color: #22283f;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body::before {
/* never visible - this is used in jQuery to check the current MQ */
content: 'mobile';
display: none;
}
@media only screen and (min-width: 1050px) {
body::before {
/* never visible - this is used in jQuery to check the current MQ */
content: 'desktop';
}
}
a {
color: #267481;
text-decoration: none;
}
/* --------------------------------
Main Components
-------------------------------- */
@media only screen and (min-width: 1050px) {
body[data-hijacking="on"] {
overflow: hidden;
}
}
.cd-section {
height: 100vh;
}
.cd-section h2 {
line-height: 100vh;
text-align: center;
font-size: 2.4rem;
}
.cd-section:first-of-type > div {
background-color: #2b334f;
}
.cd-section:first-of-type > div::before {
/* alert -> all scrolling effects are not visible on small devices */
content: 'Effects not visible on mobile!';
position: absolute;
width: 100%;
text-align: center;
top: 20px;
z-index: 2;
font-weight: bold;
font-size: 1.3rem;
text-transform: uppercase;
color: #6a7083;
}
.cd-section:nth-of-type(2) > div {
background-color: #2e5367;
}
.cd-section:nth-of-type(3) > div {
background-color: #267481;
}
.cd-section:nth-of-type(4) > div {
background-color: #fcb052;
}
.cd-section:nth-of-type(5) > div {
background-color: #f06a59;
}
[data-animation="parallax"] .cd-section > div, [data-animation="fixed"] .cd-section > div, [data-animation="opacity"] .cd-section > div {
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
[data-animation="parallax"] .cd-section:first-of-type > div, [data-animation="fixed"] .cd-section:first-of-type > div, [data-animation="opacity"] .cd-section:first-of-type > div {
background-image: url("https://unsplash.imgix.net/photo-1430620081187-c59647bac29e");
}
[data-animation="parallax"] .cd-section:nth-of-type(2) > div, [data-animation="fixed"] .cd-section:nth-of-type(2) > div, [data-animation="opacity"] .cd-section:nth-of-type(2) > div {
background-image: url("https://ununsplash.imgix.net/photo-1430126833726-4a091c572f3c");
}
[data-animation="parallax"] .cd-section:nth-of-type(3) > div, [data-animation="fixed"] .cd-section:nth-of-type(3) > div, [data-animation="opacity"] .cd-section:nth-of-type(3) > div {
background-image: url("https://ununsplash.imgix.net/photo-1428279148693-1cf2163ed67d");
}
[data-animation="parallax"] .cd-section:nth-of-type(4) > div, [data-animation="fixed"] .cd-section:nth-of-type(4) > div, [data-animation="opacity"] .cd-section:nth-of-type(4) > div {
background-image: url("https://unsplash.imgix.net/photo-1429041966141-44d228a42775");
}
[data-animation="parallax"] .cd-section:nth-of-type(5) > div, [data-animation="fixed"] .cd-section:nth-of-type(5) > div, [data-animation="opacity"] .cd-section:nth-of-type(5) > div {
background-image: url("https://unsplash.imgix.net/photo-1428959249159-5706303ea703");
}
@media only screen and (min-width: 1050px) {
.cd-section h2 {
font-size: 4rem;
font-weight: 300;
}
[data-hijacking="on"] .cd-section {
opacity: 0;
visibility: hidden;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
[data-hijacking="on"] .cd-section > div {
visibility: visible;
}
[data-hijacking="off"] .cd-section > div {
opacity: 0;
}
[data-animation="rotate"] .cd-section {
/* enable a 3D-space for children elements */
-webkit-perspective: 1800px;
-moz-perspective: 1800px;
perspective: 1800px;
}
[data-hijacking="on"][data-animation="rotate"] .cd-section:not(:first-of-type) {
-webkit-perspective-origin: center 0;
-moz-perspective-origin: center 0;
perspective-origin: center 0;
}
[data-animation="scaleDown"] .cd-section > div, [data-animation="gallery"] .cd-section > div, [data-animation="catch"] .cd-section > div {
box-shadow: 0 0 0 rgba(25, 30, 46, 0.4);
}
[data-animation="opacity"] .cd-section.visible > div {
z-index: 1;
}
}
@media only screen and (min-width: 1050px) {
.cd-section:first-of-type > div::before {
display: none;
}
}
@media only screen and (min-width: 1050px) {
.cd-section > div {
position: fixed;
top: 0;
left: 0;
width: 100%;
/* Force Hardware Acceleration */
-webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
[data-hijacking="on"] .cd-section > div {
position: absolute;
}
[data-animation="rotate"] .cd-section > div {
-webkit-transform-origin: center bottom;
-moz-transform-origin: center bottom;
-ms-transform-origin: center bottom;
-o-transform-origin: center bottom;
transform-origin: center bottom;
}
}
.cd-vertical-nav {
/* lateral navigation */
position: fixed;
z-index: 1;
right: 3%;
top: 50%;
bottom: auto;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%);
display: none;
}
.cd-vertical-nav a {
display: block;
height: 40px;
width: 40px;
/* image replace */
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
background: url(../img/cd-icon-arrow.svg) no-repeat center center;
}
.cd-vertical-nav a.cd-prev {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
margin-bottom: 10px;
}
.cd-vertical-nav a.inactive {
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 0.2s 0s, visibility 0s 0.2s;
-moz-transition: opacity 0.2s 0s, visibility 0s 0.2s;
transition: opacity 0.2s 0s, visibility 0s 0.2s;
}
@media only screen and (min-width: 1050px) {
.cd-vertical-nav {
display: block;
}
}
jQuery(document).ready(function($){
//variables
var hijacking= $('body').data('hijacking'),
animationType = $('body').data('animation'),
delta = 0,
scrollThreshold = 5,
actual = 1,
animating = false;
//DOM elements
var sectionsAvailable = $('.cd-section'),
verticalNav = $('.cd-vertical-nav'),
prevArrow = verticalNav.find('a.cd-prev'),
nextArrow = verticalNav.find('a.cd-next');
//check the media query and bind corresponding events
var MQ = deviceType();
bindEvents(MQ);
$(window).on('resize', function(){
MQ = deviceType();
bindEvents(MQ);
});
function bindEvents(MQ) {
if( MQ == 'desktop' ) {
//bind the animation to the window scroll event, arrows click and keyboard
if( hijacking == 'on' ) {
initHijacking();
$(window).on('DOMMouseScroll mousewheel', scrollHijacking);
} else {
scrollAnimation();
$(window).on('scroll', scrollAnimation);
}
prevArrow.on('click', prevSection);
nextArrow.on('click', nextSection);
$(document).on('keyup', function(event){
if( event.which=='40' && !nextArrow.hasClass('inactive') ) {
nextSection();
} else if( event.which=='38' && (!prevArrow.hasClass('inactive') || (prevArrow.hasClass('inactive') && $(window).scrollTop() != sectionsAvailable.eq(0).offset().top) ) ) {
prevSection();
}
});
//set navigation arrows visibility
checkNavigation();
} else {
//reset and unbind
resetSectionStyle();
$(window).off('DOMMouseScroll mousewheel', scrollHijacking);
$(window).off('scroll', scrollAnimation);
prevArrow.off('click', prevSection);
nextArrow.off('click', nextSection);
$(document).off('keyup');
}
}
function scrollAnimation(){
//normal scroll - use requestAnimationFrame (if defined) to optimize performance
(!window.requestAnimationFrame) ? animateSection() : window.requestAnimationFrame(animateSection);
}
function animateSection() {
var scrollTop = $(window).scrollTop(),
windowHeight = $(window).height(),
windowWidth = $(window).width();
sectionsAvailable.each(function(){
var actualBlock = $(this),
offset = scrollTop - actualBlock.offset().top;
//according to animation type and window scroll, define animation parameters
var animationValues = setSectionAnimation(offset, windowHeight, animationType);
transformSection(actualBlock.children('div'), animationValues[0], animationValues[1], animationValues[2], animationValues[3], animationValues[4]);
( offset >= 0 && offset < windowHeight ) ? actualBlock.addClass('visible') : actualBlock.removeClass('visible');
});
checkNavigation();
}
function transformSection(element, translateY, scaleValue, rotateXValue, opacityValue, boxShadow) {
//transform sections - normal scroll
element.velocity({
translateY: translateY+'vh',
scale: scaleValue,
rotateX: rotateXValue,
opacity: opacityValue,
boxShadowBlur: boxShadow+'px',
translateZ: 0,
}, 0);
}
function initHijacking() {
// initialize section style - scrollhijacking
var visibleSection = sectionsAvailable.filter('.visible'),
topSection = visibleSection.prevAll('.cd-section'),
bottomSection = visibleSection.nextAll('.cd-section'),
animationParams = selectAnimation(animationType, false),
animationVisible = animationParams[0],
animationTop = animationParams[1],
animationBottom = animationParams[2];
visibleSection.children('div').velocity(animationVisible, 1, function(){
visibleSection.css('opacity', 1);
topSection.css('opacity', 1);
bottomSection.css('opacity', 1);
});
topSection.children('div').velocity(animationTop, 0);
bottomSection.children('div').velocity(animationBottom, 0);
}
function scrollHijacking (event) {
// on mouse scroll - check if animate section
if (event.originalEvent.detail < 0 || event.originalEvent.wheelDelta > 0) {
delta--;
( Math.abs(delta) >= scrollThreshold) && prevSection();
} else {
delta++;
(delta >= scrollThreshold) && nextSection();
}
return false;
}
function prevSection(event) {
//go to previous section
typeof event !== 'undefined' && event.preventDefault();
var visibleSection = sectionsAvailable.filter('.visible'),
middleScroll = ( hijacking == 'off' && $(window).scrollTop() != visibleSection.offset().top) ? true : false;
visibleSection = middleScroll ? visibleSection.next('.cd-section') : visibleSection;
var animationParams = selectAnimation(animationType, middleScroll, 'prev');
unbindScroll(visibleSection.prev('.cd-section'), animationParams[3]);
if( !animating && !visibleSection.is(":first-child") ) {
animating = true;
visibleSection.removeClass('visible').children('div').velocity(animationParams[2], animationParams[3], animationParams[4])
.end().prev('.cd-section').addClass('visible').children('div').velocity(animationParams[0] , animationParams[3], animationParams[4], function(){
animating = false;
if( hijacking == 'off') $(window).on('scroll', scrollAnimation);
});
actual = actual - 1;
}
resetScroll();
}
function nextSection(event) {
//go to next section
typeof event !== 'undefined' && event.preventDefault();
var visibleSection = sectionsAvailable.filter('.visible'),
middleScroll = ( hijacking == 'off' && $(window).scrollTop() != visibleSection.offset().top) ? true : false;
var animationParams = selectAnimation(animationType, middleScroll, 'next');
unbindScroll(visibleSection.next('.cd-section'), animationParams[3]);
if(!animating && !visibleSection.is(":last-of-type") ) {
animating = true;
visibleSection.removeClass('visible').children('div').velocity(animationParams[1], animationParams[3], animationParams[4] )
.end().next('.cd-section').addClass('visible').children('div').velocity(animationParams[0], animationParams[3], animationParams[4], function(){
animating = false;
if( hijacking == 'off') $(window).on('scroll', scrollAnimation);
});
actual = actual +1;
}
resetScroll();
}
function unbindScroll(section, time) {
//if clicking on navigation - unbind scroll and animate using custom velocity animation
if( hijacking == 'off') {
$(window).off('scroll', scrollAnimation);
( animationType == 'catch') ? $('body, html').scrollTop(section.offset().top) : section.velocity("scroll", { duration: time });
}
}
function resetScroll() {
delta = 0;
checkNavigation();
}
function checkNavigation() {
//update navigation arrows visibility
( sectionsAvailable.filter('.visible').is(':first-of-type') ) ? prevArrow.addClass('inactive') : prevArrow.removeClass('inactive');
( sectionsAvailable.filter('.visible').is(':last-of-type') ) ? nextArrow.addClass('inactive') : nextArrow.removeClass('inactive');
}
function resetSectionStyle() {
//on mobile - remove style applied with jQuery
sectionsAvailable.children('div').each(function(){
$(this).attr('style', '');
});
}
function deviceType() {
//detect if desktop/mobile
return window.getComputedStyle(document.querySelector('body'), '::before').getPropertyValue('content').replace(/"/g, "").replace(/'/g, "");
}
function selectAnimation(animationName, middleScroll, direction) {
// select section animation - scrollhijacking
var animationVisible = 'translateNone',
animationTop = 'translateUp',
animationBottom = 'translateDown',
easing = 'ease',
animDuration = 800;
switch(animationName) {
case 'scaleDown':
animationTop = 'scaleDown';
easing = 'easeInCubic';
break;
case 'rotate':
if( hijacking == 'off') {
animationTop = 'rotation.scroll';
animationBottom = 'translateNone';
} else {
animationTop = 'rotation';
easing = 'easeInCubic';
}
break;
case 'gallery':
animDuration = 1500;
if( middleScroll ) {
animationTop = 'scaleDown.moveUp.scroll';
animationVisible = 'scaleUp.moveUp.scroll';
animationBottom = 'scaleDown.moveDown.scroll';
} else {
animationVisible = (direction == 'next') ? 'scaleUp.moveUp' : 'scaleUp.moveDown';
animationTop = 'scaleDown.moveUp';
animationBottom = 'scaleDown.moveDown';
}
break;
case 'catch':
animationVisible = 'translateUp.delay';
break;
case 'opacity':
animDuration = 700;
animationTop = 'hide.scaleUp';
animationBottom = 'hide.scaleDown';
break;
case 'fixed':
animationTop = 'translateNone';
easing = 'easeInCubic';
break;
case 'parallax':
animationTop = 'translateUp.half';
easing = 'easeInCubic';
break;
}
return [animationVisible, animationTop, animationBottom, animDuration, easing];
}
function setSectionAnimation(sectionOffset, windowHeight, animationName ) {
// select section animation - normal scroll
var scale = 1,
translateY = 100,
rotateX = '0deg',
opacity = 1,
boxShadowBlur = 0;
if( sectionOffset >= -windowHeight && sectionOffset <= 0 ) {
// section entering the viewport
translateY = (-sectionOffset)*100/windowHeight;
switch(animationName) {
case 'scaleDown':
scale = 1;
opacity = 1;
break;
case 'rotate':
translateY = 0;
break;
case 'gallery':
if( sectionOffset>= -windowHeight && sectionOffset< -0.9*windowHeight ) {
scale = -sectionOffset/windowHeight;
translateY = (-sectionOffset)*100/windowHeight;
boxShadowBlur = 400*(1+sectionOffset/windowHeight);
} else if( sectionOffset>= -0.9*windowHeight && sectionOffset< -0.1*windowHeight) {
scale = 0.9;
translateY = -(9/8)*(sectionOffset+0.1*windowHeight)*100/windowHeight;
boxShadowBlur = 40;
} else {
scale = 1 + sectionOffset/windowHeight;
translateY = 0;
boxShadowBlur = -400*sectionOffset/windowHeight;
}
break;
case 'catch':
if( sectionOffset>= -windowHeight && sectionOffset< -0.75*windowHeight ) {
translateY = 100;
boxShadowBlur = (1 + sectionOffset/windowHeight)*160;
} else {
translateY = -(10/7.5)*sectionOffset*100/windowHeight;
boxShadowBlur = -160*sectionOffset/(3*windowHeight);
}
break;
case 'opacity':
translateY = 0;
scale = (sectionOffset + 5*windowHeight)*0.2/windowHeight;
opacity = (sectionOffset + windowHeight)/windowHeight;
break;
}
} else if( sectionOffset > 0 && sectionOffset <= windowHeight ) {
//section leaving the viewport - still has the '.visible' class
translateY = (-sectionOffset)*100/windowHeight;
switch(animationName) {
case 'scaleDown':
scale = (1 - ( sectionOffset * 0.3/windowHeight)).toFixed(5);
opacity = ( 1 - ( sectionOffset/windowHeight) ).toFixed(5);
translateY = 0;
boxShadowBlur = 40*(sectionOffset/windowHeight);
break;
case 'rotate':
opacity = ( 1 - ( sectionOffset/windowHeight) ).toFixed(5);
rotateX = sectionOffset*90/windowHeight + 'deg';
translateY = 0;
break;
case 'gallery':
if( sectionOffset >= 0 && sectionOffset < 0.1*windowHeight ) {
scale = (windowHeight - sectionOffset)/windowHeight;
translateY = - (sectionOffset/windowHeight)*100;
boxShadowBlur = 400*sectionOffset/windowHeight;
} else if( sectionOffset >= 0.1*windowHeight && sectionOffset < 0.9*windowHeight ) {
scale = 0.9;
translateY = -(9/8)*(sectionOffset - 0.1*windowHeight/9)*100/windowHeight;
boxShadowBlur = 40;
} else {
scale = sectionOffset/windowHeight;
translateY = -100;
boxShadowBlur = 400*(1-sectionOffset/windowHeight);
}
break;
case 'catch':
if(sectionOffset>= 0 && sectionOffset< windowHeight/2) {
boxShadowBlur = sectionOffset*80/windowHeight;
} else {
boxShadowBlur = 80*(1 - sectionOffset/windowHeight);
}
break;
case 'opacity':
translateY = 0;
scale = (sectionOffset + 5*windowHeight)*0.2/windowHeight;
opacity = ( windowHeight - sectionOffset )/windowHeight;
break;
case 'fixed':
translateY = 0;
break;
case 'parallax':
translateY = (-sectionOffset)*50/windowHeight;
break;
}
} else if( sectionOffset < -windowHeight ) {
//section not yet visible
translateY = 100;
switch(animationName) {
case 'scaleDown':
scale = 1;
opacity = 1;
break;
case 'gallery':
scale = 1;
break;
case 'opacity':
translateY = 0;
scale = 0.8;
opacity = 0;
break;
}
} else {
//section not visible anymore
translateY = -100;
switch(animationName) {
case 'scaleDown':
scale = 0;
opacity = 0.7;
translateY = 0;
break;
case 'rotate':
translateY = 0;
rotateX = '90deg';
break;
case 'gallery':
scale = 1;
break;
case 'opacity':
translateY = 0;
scale = 1.2;
opacity = 0;
break;
case 'fixed':
translateY = 0;
break;
case 'parallax':
translateY = -50;
break;
}
}
return [translateY, scale, rotateX, opacity, boxShadowBlur];
}
});
/* Custom effects registration - feature available in the Velocity UI pack */
//none
$.Velocity
.RegisterEffect("translateUp", {
defaultDuration: 1,
calls: [
[ { translateY: '-100%'}, 1]
]
});
$.Velocity
.RegisterEffect("translateDown", {
defaultDuration: 1,
calls: [
[ { translateY: '100%'}, 1]
]
});
$.Velocity
.RegisterEffect("translateNone", {
defaultDuration: 1,
calls: [
[ { translateY: '0', opacity: '1', scale: '1', rotateX: '0', boxShadowBlur: '0'}, 1]
]
});
//scale down
$.Velocity
.RegisterEffect("scaleDown", {
defaultDuration: 1,
calls: [
[ { opacity: '0', scale: '0.7', boxShadowBlur: '40px' }, 1]
]
});
//rotation
$.Velocity
.RegisterEffect("rotation", {
defaultDuration: 1,
calls: [
[ { opacity: '0', rotateX: '90', translateY: '-100%'}, 1]
]
});
$.Velocity
.RegisterEffect("rotation.scroll", {
defaultDuration: 1,
calls: [
[ { opacity: '0', rotateX: '90', translateY: '0'}, 1]
]
});
//gallery
$.Velocity
.RegisterEffect("scaleDown.moveUp", {
defaultDuration: 1,
calls: [
[ { translateY: '-10%', scale: '0.9', boxShadowBlur: '40px'}, 0.20 ],
[ { translateY: '-100%' }, 0.60 ],
[ { translateY: '-100%', scale: '1', boxShadowBlur: '0' }, 0.20 ]
]
});
$.Velocity
.RegisterEffect("scaleDown.moveUp.scroll", {
defaultDuration: 1,
calls: [
[ { translateY: '-100%', scale: '0.9', boxShadowBlur: '40px' }, 0.60 ],
[ { translateY: '-100%', scale: '1', boxShadowBlur: '0' }, 0.40 ]
]
});
$.Velocity
.RegisterEffect("scaleUp.moveUp", {
defaultDuration: 1,
calls: [
[ { translateY: '90%', scale: '0.9', boxShadowBlur: '40px' }, 0.20 ],
[ { translateY: '0%' }, 0.60 ],
[ { translateY: '0%', scale: '1', boxShadowBlur: '0'}, 0.20 ]
]
});
$.Velocity
.RegisterEffect("scaleUp.moveUp.scroll", {
defaultDuration: 1,
calls: [
[ { translateY: '0%', scale: '0.9' , boxShadowBlur: '40px' }, 0.60 ],
[ { translateY: '0%', scale: '1', boxShadowBlur: '0'}, 0.40 ]
]
});
$.Velocity
.RegisterEffect("scaleDown.moveDown", {
defaultDuration: 1,
calls: [
[ { translateY: '10%', scale: '0.9', boxShadowBlur: '40px'}, 0.20 ],
[ { translateY: '100%' }, 0.60 ],
[ { translateY: '100%', scale: '1', boxShadowBlur: '0'}, 0.20 ]
]
});
$.Velocity
.RegisterEffect("scaleDown.moveDown.scroll", {
defaultDuration: 1,
calls: [
[ { translateY: '100%', scale: '0.9', boxShadowBlur: '40px' }, 0.60 ],
[ { translateY: '100%', scale: '1', boxShadowBlur: '0' }, 0.40 ]
]
});
$.Velocity
.RegisterEffect("scaleUp.moveDown", {
defaultDuration: 1,
calls: [
[ { translateY: '-90%', scale: '0.9', boxShadowBlur: '40px' }, 0.20 ],
[ { translateY: '0%' }, 0.60 ],
[ { translateY: '0%', scale: '1', boxShadowBlur: '0'}, 0.20 ]
]
});
//catch up
$.Velocity
.RegisterEffect("translateUp.delay", {
defaultDuration: 1,
calls: [
[ { translateY: '0%'}, 0.8, { delay: 100 }],
]
});
//opacity
$.Velocity
.RegisterEffect("hide.scaleUp", {
defaultDuration: 1,
calls: [
[ { opacity: '0', scale: '1.2'}, 1 ]
]
});
$.Velocity
.RegisterEffect("hide.scaleDown", {
defaultDuration: 1,
calls: [
[ { opacity: '0', scale: '0.8'}, 1 ]
]
});
//parallax
$.Velocity
.RegisterEffect("translateUp.half", {
defaultDuration: 1,
calls: [
[ { translateY: '-50%'}, 1]
]
});
This Pen doesn't use any external CSS resources.