This Skewed Slider with Scrolling based on Pure JS and CSS (without libraries).
A Pen by Victor Belozyorov on CodePen.
This Skewed Slider with Scrolling based on Pure JS and CSS (without libraries).
A Pen by Victor Belozyorov on CodePen.
<section class="slider-pages"> | |
<article class="js-scrolling__page js-scrolling__page-1 js-scrolling--active"> | |
<div class="slider-page slider-page--left"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--left --> | |
<div class="slider-page slider-page--right"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
<h1 class="slider-page__title slider-page__title--big"> | |
Gray & White - Skewed Slider with Scrolling | |
</h1> | |
<!-- /.slider-page__title slider-page__title--big --> | |
<h2 class="slider-page__title"> | |
Start of your story | |
</h2> | |
<!-- /.slider-page__title --> | |
<p class="slider-page__description"> | |
Please scroll down or press the down arrow on your keyboard | |
</p> | |
<!-- /.slider-page__description --> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--right --> | |
</article> | |
<!-- /.js-scrolling__page js-scrolling__page-1 js-scrolling--active --> | |
<article class="js-scrolling__page js-scrolling__page-2"> | |
<div class="slider-page slider-page--left"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
<h1 class="slider-page__title"> | |
Now you are here | |
</h1> | |
<!-- /.slider-page__title --> | |
<p class="slider-page__description"> | |
Please continue scrolling | |
</p> | |
<!-- /.slider-page__description --> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--left --> | |
<div class="slider-page slider-page--right"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--right --> | |
</article> | |
<!-- /.js-scrolling__page js-scrolling__page-2 --> | |
<article class="js-scrolling__page js-scrolling__page-3"> | |
<div class="slider-page slider-page--left"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--left --> | |
<div class="slider-page slider-page--right"> | |
<div class="slider-page--skew"> | |
<div class="slider-page__content"> | |
<h1 class="slider-page__title"> | |
Final is just the beginning | |
</h1> | |
<!-- /.slider-page__title --> | |
<p class="slider-page__description"> | |
Feel free to follow me on <a class="slider-page__link" href="https://twitter.com/WispProxy" | |
target="_blank">Twitter</a> | |
and check of <a class="slider-page__link" href="https://codepen.io/WispProxy/pens/public" | |
target="_blank">my other works</a> | |
</p> | |
<!-- /.slider-page__description --> | |
</div> | |
<!-- /.slider-page__content --> | |
</div> | |
<!-- /.slider-page--skew --> | |
</div> | |
<!-- /.slider-page slider-page--right --> | |
</article> | |
<!-- /.js-scrolling__page js-scrolling__page-3 --> | |
</section> | |
<!-- /.slider-pages --> |
/********************* | |
* Helpers Code | |
********************/ | |
/** | |
* @function DOMReady | |
* | |
* @param callback | |
* @param element | |
* @param listener | |
* @returns {*} | |
* @constructor | |
*/ | |
const DOMReady = (( | |
callback = () => {}, | |
element = document, | |
listener = 'addEventListener' | |
) => { | |
return (element[listener]) ? element[listener]('DOMContentLoaded', callback) : window.attachEvent('onload', callback); | |
}); | |
/** | |
* @function ProjectAPI | |
* | |
* @type {{hasClass, addClass, removeClass}} | |
*/ | |
const ProjectAPI = (() => { | |
let hasClass, | |
addClass, | |
removeClass; | |
hasClass = ((el, className) => { | |
if (el === null) { | |
return; | |
} | |
if (el.classList) { | |
return el.classList.contains(className); | |
} | |
else { | |
return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); | |
} | |
}); | |
addClass = ((el, className) => { | |
if (el === null) { | |
return; | |
} | |
if (el.classList) { | |
el.classList.add(className); | |
} | |
else if (!hasClass(el, className)) { | |
el.className += ' ' + className | |
} | |
}); | |
removeClass = ((el, className) => { | |
if (el === null) { | |
return; | |
} | |
if (el.classList) { | |
el.classList.remove(className); | |
} | |
else if (hasClass(el, className)) { | |
let reg = new RegExp('(\\s|^)' + className + '(\\s|$)'); | |
el.className = el.className.replace(reg, ' '); | |
} | |
}); | |
return { | |
hasClass: hasClass, | |
addClass: addClass, | |
removeClass: removeClass | |
}; | |
})(); | |
/********************* | |
* Application Code | |
********************/ | |
/** | |
* @function readyFunction | |
* | |
* @type {Function} | |
*/ | |
const readyFunction = (() => { | |
const KEY_UP = 38; | |
const KEY_DOWN = 40; | |
let scrollingClass = 'js-scrolling', | |
scrollingActiveClass = scrollingClass + '--active', | |
scrollingInactiveClass = scrollingClass + '--inactive', | |
scrollingTime = 1350, | |
scrollingIsActive = false, | |
currentPage = 1, | |
countOfPages = document.querySelectorAll('.' + scrollingClass + '__page').length, | |
prefixPage = '.' + scrollingClass + '__page-', | |
_switchPages, | |
_scrollingUp, | |
_scrollingDown, | |
_mouseWheelEvent, | |
_keyDownEvent, | |
init; | |
/** | |
* @function _switchPages | |
* | |
* @private | |
*/ | |
_switchPages = () => { | |
let _getPageDomEl; | |
/** | |
* @function _getPageDomEl | |
* | |
* @param page | |
* @returns {Element} | |
* @private | |
*/ | |
_getPageDomEl = (page = currentPage) => { | |
return document.querySelector(prefixPage + page); | |
}; | |
scrollingIsActive = true; | |
ProjectAPI.removeClass( | |
_getPageDomEl(), | |
scrollingInactiveClass | |
); | |
ProjectAPI.addClass( | |
_getPageDomEl(), | |
scrollingActiveClass | |
); | |
ProjectAPI.addClass( | |
_getPageDomEl(currentPage - 1), | |
scrollingInactiveClass | |
); | |
ProjectAPI.removeClass( | |
_getPageDomEl(currentPage + 1), | |
scrollingActiveClass | |
); | |
setTimeout( | |
() => { | |
return scrollingIsActive = false; | |
}, | |
scrollingTime | |
); | |
}; | |
/** | |
* @function _scrollingUp | |
* | |
* @private | |
*/ | |
_scrollingUp = () => { | |
if (currentPage === 1) { | |
return; | |
} | |
currentPage--; | |
_switchPages(); | |
}; | |
/** | |
* @function _scrollingDown | |
* | |
* @private | |
*/ | |
_scrollingDown = () => { | |
if (currentPage === countOfPages) { | |
return; | |
} | |
currentPage++; | |
_switchPages(); | |
}; | |
/** | |
* @function _mouseWheelEvent | |
* | |
* @param e | |
* @private | |
*/ | |
_mouseWheelEvent = (e) => { | |
if (scrollingIsActive) { | |
return; | |
} | |
if (e.wheelDelta > 0 || e.detail < 0) { | |
_scrollingUp(); | |
} | |
else if (e.wheelDelta < 0 || e.detail > 0) { | |
_scrollingDown(); | |
} | |
}; | |
/** | |
* @function _keyDownEvent | |
* | |
* @param e | |
* @private | |
*/ | |
_keyDownEvent = (e) => { | |
if (scrollingIsActive) { | |
return; | |
} | |
let keyCode = e.keyCode || e.which; | |
if (keyCode === KEY_UP) { | |
_scrollingUp(); | |
} | |
else if (keyCode === KEY_DOWN) { | |
_scrollingDown(); | |
} | |
}; | |
/** | |
* @function init | |
* | |
* @note auto-launch | |
*/ | |
init = (() => { | |
document.addEventListener( | |
'mousewheel', | |
_mouseWheelEvent, | |
false | |
); | |
document.addEventListener( | |
'DOMMouseScroll', | |
_mouseWheelEvent, | |
false | |
); | |
document.addEventListener( | |
'keydown', | |
_keyDownEvent, | |
false | |
); | |
})(); | |
}); | |
/** | |
* Launcher | |
*/ | |
DOMReady(readyFunction); |
/*********************** | |
* Variables | |
**********************/ | |
$font-family: 'Open Sans', sans-serif; | |
$font-size: 1em; | |
$color-body: #282828; | |
$color-text: #e2e2e2; | |
$color-link: #80a1c1; | |
$color-link-active: #6386a9; | |
$variable-skewX: 18deg; | |
$variable-vHForSkewX: 32.5vh; | |
$variable-scrollingTime: 1350ms; | |
/*********************** | |
* Project Main Styles | |
**********************/ | |
*, | |
*:before, | |
*:after { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
font-family: $font-family; | |
background-color: $color-body; | |
} | |
.slider-pages { | |
overflow: hidden; | |
position: relative; | |
height: 100vh; | |
} | |
.slider-page { | |
position: absolute; | |
top: 0; | |
width: 50%; | |
height: 100vh; | |
transition: transform $variable-scrollingTime; | |
} | |
.slider-page--skew { | |
overflow: hidden; | |
position: absolute; | |
top: 0; | |
width: 140%; | |
height: 100%; | |
background: $color-body; | |
transform: skewX($variable-skewX * -1); | |
} | |
.slider-page--left { | |
left: 0; | |
transform: translateX($variable-vHForSkewX * -1) | |
translateY(100%) | |
translateZ(0); | |
.slider-page--skew { | |
left: -40%; | |
} | |
.slider-page__content { | |
padding: auto 30% auto 30%; | |
transform-origin: 100% 0; | |
} | |
} | |
.slider-page--right { | |
left: 50%; | |
transform: translateX($variable-vHForSkewX) | |
translateY(-100%) | |
translateZ(0); | |
.slider-page--skew { | |
right: -40%; | |
} | |
.slider-page__content { | |
padding: auto 30% auto 30%; | |
transform-origin: 0 100%; | |
} | |
} | |
.slider-page__content { | |
position: absolute; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-flow: column wrap; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
padding: 0 30% 0 30%; | |
color: $color-text; | |
background-size: cover; | |
transform: skewX($variable-skewX); | |
transition: transform $variable-scrollingTime; | |
} | |
.slider-page__title { | |
margin-bottom: 1em; | |
font-size: $font-size; | |
text-align: center; | |
text-transform: uppercase; | |
} | |
.slider-page__title--big { | |
font-size: $font-size * 1.2; | |
} | |
.slider-page__description { | |
font-size: $font-size; | |
text-align: center; | |
} | |
.slider-page__link { | |
color: $color-link; | |
&:hover, | |
&:focus { | |
color: $color-link-active; | |
text-decoration: none; | |
} | |
} | |
/*********************** | |
* Project JS Styles | |
**********************/ | |
.js-scrolling__page { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
} | |
.js-scrolling--active { | |
.slider-page { | |
transform: translateX(0) | |
translateY(0) | |
translateZ(0); | |
} | |
} | |
.js-scrolling--inactive { | |
.slider-page__content { | |
transform: skewX($variable-skewX) | |
scale(.9); | |
} | |
} | |
.js-scrolling__page-1 { | |
.slider-page--left .slider-page__content { | |
background-image: url("https://s-media-cache-ak0.pinimg.com/originals/a6/6a/a3/a66aa3134eb9f439838e676297a75bd6.jpg"); | |
} | |
.slider-page--right .slider-page__content { | |
background-color: $color-body; | |
} | |
} | |
.js-scrolling__page-2 { | |
.slider-page--left .slider-page__content { | |
background-color: $color-text; | |
} | |
.slider-page--left .slider-page__title, | |
.slider-page--left .slider-page__description { | |
color: $color-body; | |
} | |
.slider-page--right .slider-page__content { | |
background-image: url("https://s-media-cache-ak0.pinimg.com/originals/7a/8d/51/7a8d51f4968960334274ac7959d31a7d.jpg"); | |
} | |
} | |
.js-scrolling__page-3 { | |
.slider-page--left .slider-page__content { | |
background-image: url("https://s-media-cache-ak0.pinimg.com/originals/4c/d8/7b/4cd87bc93cca92f76285c061cef16585.jpg"); | |
} | |
.slider-page--right .slider-page__content { | |
background-color: $color-body; | |
} | |
} |