JSFiddle - React, Tailwind, and code Playground
by davidxmartins
HTML
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Horizontal Scroll</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://corentinfardeau.github.io/horizontal-scroll/index.js"></script>
</head>
<body>
<div class="container">
<div id="welcome" class="block">
<h2>Item 1</h2>
</div>
<div id="services" class="block grey">
<h2>Item 2</h2>
</div>
<div id="about" class="block">
<h2>Item 3</h2>
</div>
<div id="contacts" class="block grey">
<h2>Item 4</h2>
</div>
<div id="articles" class="block">
<h2>Item 4</h2>
</div>
</div>
<script>
var blocks = document.getElementsByClassName('block');
var container = document.getElementsByClassName('container');
var hs = new HorizontalScroll.default({
blocks : blocks,
container: container,
isAnimated: false,
springEffect: 0.8
});
</script>
<!-- MENU _____________________ -->
<header class="large">
<nav>
<a href="#welcome"><div class="logo"></div></a>
<ul>
<li><a href="#welcome">Welcome</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contacts">Contacts</a></li>
<li><a href="#articles">Library</a></li>
</ul>
</nav>
</header>
</body>
</html>
CSS
html, body {
width: 100%;
height: 100%;
overflow: hidden;
scroll-behavior: smooth;
}
body {
margin: 0;
}
.block{
width: 100vw;
height: 100vh;
margin: 0;
}
.grey{ background: #ccc; }
.container{
scroll-behavior: smooth;
}
/* MENU _____________________ */
.logo {
float: left;
}
nav {
width: 100%;
}
/* HEADER */
header {
float: left;
width: 100%;
position: absolute;
z-index: 9999999;
top: 0;
}
/* HEADER LARGE */
header.large {
height: 50px;
}
header.large .logo {
width: 225px;
height: 50px;
margin: 20px 0 0 20px;
background: url('../images/logo-fireqa-green-500px.png');
background-repeat: no-repeat;
background-size: contain;
transition: 0.7s all;
-moz-transition: 0.7s all;
-webkit-transition: 0.7s all;
-o-transition: 0.7s all;
}
/* UNORDERED LIST */
header.large ul {
list-style: none;
float: right;
margin-right: 25px;
}
header.small ul {
list-style: none;
float: right;
margin: 0;
}
header.large li {
display: inline;
float: left;
list-style-position: inside;
height: 50px;
-webkit-transition: all ease 0.3s;
-moz-transition: all ease 0.3s;
transition: all 0.3s ease-in-out;
}
header.large li a {
display: block;
padding: 20px;
color: #0E6245;
text-decoration: none;
font-family: 'Montserrat', 'arial', sans-serif;
font-weight: 600 !important;
letter-spacing: -1px;
font-size: 25px;
background-image: linear-gradient(#0E6245, #0E6245);
background-position: 50% 80%;
background-repeat: no-repeat;
background-size: 0% 4px;
-moz-transition: all 0.3s ease-in-out 0s;
-ms-transition: all 0.3s ease-in-out 0s;
-o-transition: all 0.3s ease-in-out 0s;
-webkit-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out 0s;
}
header.large li a:hover, a:focus {
background-size: 60%...
JavaScript
import { EventEmitter } from 'events';
import VirtualScroll from 'virtual-scroll';
import raf from 'raf';
import transform from 'prefix';
export default class HorizontalScroll extends EventEmitter {
constructor(opts) {
super();
this._bind();
// Set default options
this.options = Object.assign({
container: opts.container,
blocks: opts.blocks,
isAnimated: opts.isAnimated || false,
spring: opts.spring || 0.1,
skewReducer: opts.skewReducer || 20,
skewLimit: opts.skewLimit || 30,
}, opts);
this.vars = {
scrollValue: 0,
oldScrollValue: 0,
scrollTarget: 0,
scrollLeft: 0,
scrollRight: 0,
spring: this.options.spring,
direction: 0,
speed: 0,
speedTarget: 0,
};
this.wrapper = document.createElement('div');
this.wrapper.setAttribute('class', 'horizontal-scroll');
this.vs = new VirtualScroll();
this.transform = transform('transform');
this.raf = raf;
this._setUI();
this._addEvents();
this.onResize();
}
// PRIVATE
/**
* Biding methods
*
*/
_bind() {
this._update = this._update.bind(this);
this.onResize = this.onResize.bind(this);
}
/**
* Add all events
*
*/
_addEvents() {
this.vs.on(this._onScroll, this);
this.raf(this._update);
window.addEventListener('resize', this.onResize);
}
/**
* Remove all events
*
*/
_removeEvents() {
this.raf.cancel(this._update);
this.raf(this._update);
window.removeEventListener('resize', this.onResize);
}
/**
* Set the UI
*
*/
_setUI() {
Object.assign(this.wrapper.style ,{
position: 'absolute',
top: '0',
left: '0',
'backface-visibility': 'hidden',
'will-change': 'transform'
});
Object.assign(this.options.container[0].style ,{
'white-space': 'nowrap',
'position': 'relative',
});
Array.prototype.forEach.call(this.options.blocks, block => {
block.style.display = 'inline-block';
this.options.container[0].replaceChild(this.wrapper,...