flip scroll when scrolling - javascript

We need advice on how to do what would happen with normal scrolling of the page (with a wheel, or in a mob with a finger) after the block has been screwed up to the top of the screen, it began to scroll horizontally and after the edge of the block is reached, the standard scroll continues, respectively, if the scroll goes up, then that's it in reverse order. (There may be several such blocks on a page)
* {
box-sizing: border-box;
margin: 0;
}
body {
overflow-x: hidden;
}
.simple {
height: 100vh;
background: #1f69c0;
border-bottom: 2px solid #777;
}
.simple2 {
height: 400px;
background: #EEAA07;
border-bottom: 2px solid #777;
}
.simple3 {
height: 400px;
background: #07eed9;
border-bottom: 2px solid #777;
}
.outer {
height: 150px;
background: #7b8e39;
overflow-y: hidden;
overflow-x: scroll;
}
.inner {
height: 100%;
margin: 0 100px;
display: flex;
}
.cube {
min-width: 200px;
height: 100px;
background: #f6f6f6;
margin: 10px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="simple"></div>
<div class="outer">
<div class="inner">
<div class="cube">1</div>
<div class="cube">2</div>
<div class="cube">3</div>
<div class="cube">4</div>
<div class="cube">5</div>
<div class="cube">6</div>
<div class="cube">7</div>
<div class="cube">8</div>
<div class="cube">9</div>
<div class="cube">10</div>
</div>
</div>
<div class="simple2"></div>
<div class="simple3"></div>
Here is an approximate structure, until block 2 has scrolled to the end, block 3 should be visible and after 2 has scrolled horizontally to the end, the standard scroll will continue
PS Here is an example (https://horizontalscrolling.wpdemos.net/horizontal-scrolling/) of how scrolling should work, although there can be more than 1 block on one screen

This technique needs to use javascript called "GSAP" which is a high-performance javascript animation library.
I found a similar animation that you were looking for.
Hopefully, this will help :)
//https://codepen.io/osublake/pen/e72106811a34efcccff91a03568cc790.js?v=3
class SmoothScroll {
constructor(options) {
this.endThreshold = 0.05;
this.requestId = null;
this.maxDepth = 10;
this.viewHeight = 0;
this.halfViewHeight = 0;
this.maxDistance = 0;
this.viewWidth = 0;
this.halfViewWidth = 0;
this.maxDistanceWidth = 0;
this.scrollHeight = 0;
this.endScroll = 0;
this.returnCurrentScroll = 0;
this.currentScroll = 0;
this.scrollTransform = 0;
this.horizontalScroll = 0;
this.resizeRequest = 1;
this.scrollRequest = 0;
this.scrollItems = [];
this.lastTime = -1;
this.maxElapsedMS = 100;
this.targetFPMS = 0.06;
// this.scrollBody = options.scrollBody;
// this.scrollSpacer = options.scrollSpacer;
this.target = options.target;
this.scrollEase = options.scrollEase != null ? options.scrollEase : 0.1;
this.maxOffset = options.maxOffset != null ? options.maxOffset : 500;
this.horizontalScrollWrapper = options.horizontalScrollWrapper;
this.horizontalScrollTarget = options.horizontalScrollTarget;
this._horziontalSetHeihgt();
this.childElements = this._childElements();
this.rectHorStart = this.horizontalScrollWrapper.getBoundingClientRect();
this.horzItemStart = {
top: this.rectHorStart.top,
bottom: this.rectHorStart.bottom,
height: this.rectHorStart.height
}
this.addItems();
window.addEventListener("resize", this._onResize);
window.addEventListener("scroll", this._onScroll);
//this.scrollBody.addEventListener("scroll", this._onScroll);
this._update();
}
_childElements = (event) => {
const childElementsNode = this.target.querySelectorAll("*[data-color]");
return childElementsNode;
}
_horizonstalScrollRect = (event) => {
const horzintalRect = this.horizontalScrollTarget.getBoundingClientRect();
return horzintalRect;
}
_lastScrollRect = (event) => {
const lastScrollRect = this.horizontalScrollTarget.lastElementChild.getBoundingClientRect();
return lastScrollRect;
}
_horziontalSetHeihgt = (event) => {
let horScrHeight = 0;
if (
this.horizontalScrollTarget !== null &&
this.horizontalScrollWrapper !== null
) {
const lastScrollRect = this._lastScrollRect();
horScrHeight = this.horizontalScrollTarget.scrollWidth - lastScrollRect.width + this._horizonstalScrollRect().height;
this.horizontalScrollWrapper.style.height = horScrHeight + "px";
}
}
_onResize = (event) => {
this.resizeRequest++;
if (!this.requestId) {
this.lastTime = performance.now();
this.requestId = requestAnimationFrame(this._update);
}
};
_onScroll = (event) => {
this.scrollRequest++;
if (!this.requestId) {
this.lastTime = performance.now();
this.requestId = requestAnimationFrame(this._update);
}
};
_horizonstalScroll = (scrollY,dt) => {
if (this.horizontalScrollWrapper !== null) {
const rectHor = this.horizontalScrollWrapper.getBoundingClientRect();
const lastScrollRect = this._lastScrollRect();
const itemHor = {
target: this.horizontalScrollTarget,
targetRect: this._horizonstalScrollRect(),
top: rectHor.top,
bottom: rectHor.bottom + scrollY,
topScroll: rectHor.top + scrollY,
horizonstalMove: 0,
};
itemHor.horizonstalMove += this.currentScroll - this.horzItemStart.top;
if(scrollY >= this.horzItemStart.top && scrollY <= this.horzItemStart.bottom - itemHor.targetRect.height){
itemHor.target.style.position = 'fixed';
itemHor.target.style.transform = `translate3d(-${itemHor.horizonstalMove}px,0px,0px)`;
//this._paralaxHorizontal(dt);
if(lastScrollRect.x <= (lastScrollRect.width/2)){
this.scrollTransform = this.horzItemStart.bottom - itemHor.targetRect.height;
itemHor.target.style.top = this.horzItemStart.bottom - itemHor.targetRect.height+'px';
}else {
this.scrollTransform = this.horzItemStart.top;
itemHor.target.style.top = this.horzItemStart.top+'px';
}
}
}
};
_changeColorBody = (event) => {
if(this.childElements.length > 0){
this.childElements.forEach(child => {
const wrapper = document.querySelector('.change_color_page');
const childRect = child.getBoundingClientRect();
const childAttr = child.getAttribute('data-color');
if(childRect.y <= this.halfViewHeight && childRect.bottom >= this.halfViewHeight){
if(childAttr == "off_white"){
if(!document.body.classList.contains('white')){
document.body.classList.add('white');
}
if(!wrapper.classList.contains('white')){
wrapper.classList.add('white');
}
}else if(childAttr == "dark"){
if(document.body.classList.contains('white')){
document.body.classList.remove('white');
}
if(wrapper.classList.contains('white')){
wrapper.classList.remove('white');
}
}
}
});
}
}
_update = (currentTime = performance.now()) => {
let elapsedMS = currentTime - this.lastTime;
if (elapsedMS > this.maxElapsedMS) {
elapsedMS = this.maxElapsedMS;
}
const deltaTime = elapsedMS * this.targetFPMS;
const dt = 1 - Math.pow(1 - this.scrollEase, deltaTime);
const resized = this.resizeRequest > 0;
const scrollY = window.pageYOffset;
//const scrollY = this.scrollBody.scrollTop;
if (resized) {
this._horziontalSetHeihgt();
const height = this.target.clientHeight;
document.body.style.height = height + "px";
//this.scrollSpacer.style.height = height + "px";
this.scrollHeight = height;
this.viewHeight = window.innerHeight;
this.halfViewHeight = this.viewHeight / 2;
this.maxDistance = this.viewHeight * 2;
this.resizeRequest = 0;
this.viewWidth = window.innerWidth;
this.halfViewWidth = this.viewWidth / 2;
this.maxDistanceWidth = this.viewWidth * 2;
}
this.endScroll = scrollY;
// this.scrollTransform += (scrollY - this.scrollTransform) * this.scrollEase;
this.scrollTransform += (scrollY - this.scrollTransform) * dt;
this.currentScroll += (scrollY - this.currentScroll) * dt;
if (Math.abs(scrollY - this.currentScroll) < this.endThreshold || resized) {
this.currentScroll = scrollY;
this.scrollRequest = 0;
}
if (
Math.abs(scrollY - this.scrollTransform) < this.endThreshold ||
resized
) {
this.scrollTransform = scrollY;
this.scrollRequest = 0;
}
///change color section
this._changeColorBody();
///horizontal scroll
this._horizonstalScroll(this.currentScroll,dt);
// const scrollOrigin = scrollY + this.halfViewHeight;
const scrollOrigin = this.currentScroll + this.viewHeight;
this.target.style.transform = `translate3d(0px,-${this.scrollTransform}px,0px)`;
//items
for (let i = 0; i < this.scrollItems.length; i++) {
const item = this.scrollItems[i];
const distance = scrollOrigin - item.top;
const offsetRatio = distance / this.maxDistance;
item.endOffset = Math.round(
this.maxOffset * item.depthRatio * offsetRatio
);
if (Math.abs(item.endOffset - item.currentOffset < this.endThreshold)) {
item.currentOffset = item.endOffset;
} else {
// item.currentOffset += (item.endOffset - item.currentOffset) * this.scrollEase;
item.currentOffset += (item.endOffset - item.currentOffset) * dt;
}
if(item.direction == "y"){
item.target.style.transform = `translate3d(0px,${item.currentOffset}px,0px)`;
}else if(item.direction == "x"){
item.target.style.transform = `translate3d(${item.currentOffset}px,0px,0px)`;
}
}
this.lastTime = currentTime;
this.requestId =
this.scrollRequest > 0 ? requestAnimationFrame(this._update) : null;
};
addItems() {
this.scrollItems = [];
const elements = document.querySelectorAll("*[data-depth]");
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const depth = +element.getAttribute("data-depth");
const direction_item = element.getAttribute("data-direction");
const rect_item = element.getBoundingClientRect();
const item = {
rect: rect_item,
target: element,
top: rect_item.top + window.pageYOffset,
//top: rect_item.top + this.scrollBody.scrollTop,
depth: depth,
depthRatio: depth / this.maxDepth,
currentOffset: 0,
endOffset: 0,
direction: direction_item
};
this.scrollItems.push(item);
}
return this;
}
currentScrollReturn() {
return this.currentScroll;
}
}
document.documentElement.style.setProperty(
"--scrollbar-size",
getScrollbarSize() + "px"
);
var scroller = new SmoothScroll({
// scrollBody: document.querySelector(".scroll-content"),
// scrollSpacer: document.querySelector(".spacer"),
target: document.querySelector(".scroll-container"), // element container to scroll
scrollEase: 0.05,
horizontalScrollWrapper: document.querySelector(".horizontal-scroll-wrapper"),
horizontalScrollTarget: document.querySelector(".horizontal-scroll")
});
function getScrollbarSize() {
var div = document.createElement("div");
div.classList.add("scrollbar-test");
document.body.appendChild(div);
var size = div.offsetWidth - div.scrollWidth;
document.body.removeChild(div);
return size;
}
$white: #fbe8ee;
$black: #0a0a0a;
:root {
--scrollbar-size: 0px;
}
*, :after, :before {
box-sizing: border-box;
}
body {
}
.viewport {
overflow: hidden;
position: fixed;
height: 100%;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
body {
overflow-x: hidden;
overflow-y: scroll;
padding: 0;
margin: 0;
font-family: "Courier New", Courier, monospace;
*:not(.change_color_page) {
color: $white;
transition: color 0.5s ease-in-out, border-color 0.5s ease;
border-color: $white;
}
&.white {
*:not(.change_color_page) {
color: $black;
transition: color 0.5s ease-in-out, border-color 0.5s ease;
border-color: $black;
}
}
}
.change_color_page {
position: fixed;
display: block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: $black;
transition: background-color 0.5s ease;
backface-visibility: hidden;
transform-style: preserve-3d;
&.white {
background-color: $white;
}
}
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.5s ease-in-out;
background-color: $white;
&.white {
background-color: $black;
}
}
.scrollbar-test {
position: absolute;
visibility: hidden;
overflow: scroll;
width: 100px;
height: 100px;
top: -99999px;
left: -99999px;
pointer-events: none;
user-select: none;
}
.fixed-content {
position: absolute;
display: block;
top: 0;
left: 0;
right: var(--scrollbar-size, 0px);
bottom: 0;
z-index: 2;
pointer-events: none;
}
.scroll-container {
position: absolute;
overflow: hidden;
z-index: 10;
backface-visibility: hidden;
transform-style: preserve-3d;
width: 100%;
}
.content {
overflow: hidden;
position: relative;
width: 100%;
}
.spacer {
background: transparent;
}
.single-item {
flex: 0 0 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 70px;
&.left {
justify-content: flex-start;
}
p {
width: 300px;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
border-width: 2px;
border-style: solid;
}
}
.horizontal-scroll-wrapper {
position: relative;
}
.horizontal-scroll {
display: flex;
}
.horizontal-scroll .single-item {
flex: 0 0 100vw;
p {
width: 600px;
height: 600px;
max-width: 80%;
max-height: 80%;
}
}
<div class="change_color_page"></div>
<header></header>
<div class="viewport">
<div class="scroll-container">
<div class="content">
<div class="single-item active" data-color="off_white">
<p>1</p>
</div>
<div class="single-item" data-color="dark">
<p data-depth="-7" data-direction="y">2</p>
</div>
<div class="single-item" data-color="off_white">
<p class="item_to_move">3</p>
</div>
<div class="single-item" data-color="dark">
<p data-depth="-3" data-direction="y">4</p>
</div>
<div class="single-item" data-color="off_white">
<p data-depth="-3" data-direction="y">5</p>
</div>
<div class="horizontal-scroll-wrapper" data-color="dark">
<div class="horizontal-scroll">
<div class="single-item">
<p><span data-depth-hor="-3" data-direction="left">6</span></p>
</div>
<div class="single-item">
<p><span data-depth-hor="-3" data-direction="left">7</span></p>
</div>
<div class="single-item">
<p><span data-depth-hor="-3" data-direction="left">8</span></p>
</div>
<div class="single-item">
<p><span data-depth-hor="-3" data-direction="left">9</span></p>
</div>
<div class="single-item">
<p><span data-depth-hor="-3" data-direction="left">10</span></p>
</div>
</div>
</div>
<div class="single-item" data-color="off_white">
<p data-depth="-3" data-direction="y">11</p>
</div>
<div class="single-item" data-color="dark">
<p data-depth="-3" data-direction="y">12</p>
</div>
<div class="single-item left" data-color="off_white">
<p data-depth="15" data-direction="x">13</p>
</div>
</div>
</div>
</div>
source code from: https://codepen.io/duty47/pen/vYYEgam

Related

How to create infinite loop slider using offset in vanilla JS?

So I am working on this project and I made a slider that slides 3 pics at a time but when it comes to the last 3 pics it stops (because of the condition) but I want to make it into infinite loop and I want it to autoslide every 3 seconds. Does anybody know how I can rewrite this part of code to make this work?
const carousel = document.querySelector(".carouselSlides");
const card = carousel.querySelector(".card");
const leftButton = document.querySelector(".slideLeft");
const rightButton = document.querySelector(".slideRight");
const carouselWidth = carousel.offsetWidth;
const cardStyle = card.currentStyle || window.getComputedStyle(card);
const cardMarginRight = Number(cardStyle.marginRight.match(/\d+/g)[0]);
const cardCount = carousel.querySelectorAll(".card").length;
let offset = 0;
const maxX = -(
(cardCount / 3) * carouselWidth +
cardMarginRight * (cardCount / 3) -
carouselWidth -
cardMarginRight
);
leftButton.addEventListener("click", function() {
if (offset !== 0) {
offset += carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
});
rightButton.addEventListener("click", function() {
if (offset !== maxX) {
offset -= carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
});
.carouselContainer {
display: flex;
align-items: center;
justify-content: space-around;
position: relative;
overflow: hidden;
height: 58vh;
width: 92vw;
margin: 0 auto;
}
.carouselSlides {
display: flex;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
position: absolute;
left: 0;
transition: all 1s ease;
}
.button-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
}
.slideLeft {
position: relative;
color: #f1f1f1;
background-color: transparent;
border: none;
font-size: 4rem;
right: 26rem;
}
.slideRight {
position: relative;
color: #f1f1f1;
background-color: transparent;
border: none;
font-size: 4rem;
left: 26rem;
}
<div class="carouselContainer">
<div class="carouselSlides">
<div id="slide0" class="card">
<div class="card__thumbnail">
<span class="card__title">FADE</span>
<button class="morebtn" onclick="">READ MORE</button>
</div>
</div>
</div>
<div class="button-wrapper">
<button class="slideLeft">‹</button>
<button class="slideRight">›</button>
</div>
</div>

Best replacement for scrollBy

I have a carousel that I have to hard code and I need some help. I want to make a slide effect for mobile phones but I can't find a replacement for album.scrollBy. If you take a look at the code, you can see that on touchMove I scroll the parent element of the carousel but after the touch is done I transform the carousel and the album remains scrolled. So the only solution I found was to remove the scroll after the transition but is doesn't look good. Any ideas?
This is the carousel index.html
<body>
<div id="album" autoCall="true" class='album'>
<ul id="carousel" class='carousel is-set'>
<li class='container carousel-element'>
<img src="assets/img1.jpeg">
</li>
<li class='container carousel-element'>
<img src="assets/img2.jpeg">
</li>
<li class='container carousel-element'>
<img src="assets/img3.jpeg">
</li>
<li class='container carousel-element is-ref'>
<img src="assets/img4.jpeg">
</li>
</ul>
<div class="left-arrow"></div>
<div class="right-arrow"></div>
</div>
<script src="SLID/js/index.js"></script>
</body>
This is the CSS file that contains the transitions:
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
scroll-behavior: smooth;
}
.album {
overflow: hidden;
width: 100%;
height: 100%;
margin: auto;
position: relative;
}
.carousel {
height: 100%;
width: 100%;
display: flex;
left: -100%;
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.carousel.toNext {
transform: translateX(100%);
}
.carousel.toPrev {
transform: translateX(-100%);
}
.carousel.is-set {
transform: none;
transition: transform 0.5s cubic-bezier(0.215, 0.610, 0.355, 1);
}
.carousel-element {
background: #ddd;
flex: 1 0 100%;
text-align: center;
order: 2;
position: relative;
height: 100% !important;
max-width: 100% !important;
padding: 0;
}
.carousel-element:nth-child(even) {
background: #d5d5d5;
}
.carousel-element.is-ref {
order: 1;
}
.controls {
padding: 2em;
text-align: center;
}
.container {
margin: 0 auto;
height: 100%;
width: 100%;
}
.carousel-element >img, video {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
max-width: 100%;
max-height: 100%;
margin: auto;
padding: 0 !important;
}
.left-arrow,
.right-arrow {
height: 100%;
position: absolute;
top: 0;
bottom: 0;
z-index: 1;
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center;
width: 15%;
color: #fff;
text-align: center;
opacity: .5;
transition: opacity .15s ease
}
.left-arrow {
left: 0;
background: red
}
.right-arrow {
right: 0;
background: blue;
}
And here is the JS file:
let album = document.getElementById("album");
let carousel = document.getElementById("carousel");
let seats = document.querySelectorAll("ul > li");
if (seats.length === 1)
carousel.style.left = 0;
class SLID {
constructor() {
this.nextDisable = false;
this.prevDisable = false;
this.startX = 0;
this.finalX = 0;
this.lastX = 0;
this.didTheTouchMove = false;
}
goToNext() {
this.nextDisable = true;
var el, i, j, new_seat, ref;
el = document.querySelector("ul > li.is-ref");
el.classList.remove('is-ref');
new_seat = el.nextElementSibling || seats[0];
new_seat.classList.add('is-ref');
new_seat.style.order = 1;
for (i = j = 2, ref = seats.length; (2 <= ref ? j <= ref : j >= ref); i = 2 <= ref ? ++j : --j) {
new_seat = new_seat.nextElementSibling || seats[0];
new_seat.style.order = i;
}
carousel.classList.remove('toPrev');
carousel.classList.add('toNext');
carousel.classList.remove('is-set');
document.getElementById('carousel').addEventListener("transitionend", () => {
this.nextDisable = false;
}, {
once: true,
});
return setTimeout((function () {
return carousel.classList.add('is-set');
}), 50);
}
goToPrev() {
this.prevDisable = true;
var el, i, j, new_seat, ref;
el = document.querySelector("ul > li.is-ref");
el.classList.remove('is-ref');
new_seat = el.previousElementSibling || seats[seats.length - 1];
new_seat.classList.add('is-ref');
new_seat.style.order = 1;
for (i = j = 2, ref = seats.length; (2 <= ref ? j <= ref : j >= ref); i = 2 <= ref ? ++j : --j) {
new_seat = new_seat.nextElementSibling || seats[0];
new_seat.style.order = i;
}
carousel.classList.remove('toNext');
carousel.classList.add('toPrev');
carousel.classList.remove('is-set');
document.getElementById('carousel').addEventListener("transitionend", () => {
this.prevDisable = false;
}, {
once: true
});
return setTimeout((function () {
return carousel.classList.add('is-set');
}), 50);
}
}
if (document.getElementById("album").getAttribute('autoCall') === "true") {
let s = new SLID();
document.addEventListener("keydown", (e) => {
if (e.keyCode === 37)
if (s.prevDisable === false)
s.goToPrev();
if (e.keyCode === 39)
if (s.nextDisable === false)
s.goToNext();
})
carousel.addEventListener("touchstart", (e) => {
s.startX = e.touches[0].clientX;
s.lastX = e.touches[0].clientX;
})
carousel.addEventListener("touchmove", (e) => {
album.scrollBy(s.lastX - e.touches[0].clientX, 0);
s.lastX = e.touches[0].clientX;
})
carousel.addEventListener("touchend", (e) => {
album.scrollBy(s.lastX - s.startX, 0);
s.goToNext();
})
}

javascript requestAnimationFrame final position never exact

let pf = document.querySelectorAll('.pf');
for (let i of pf) {
Object.assign(i.style, {
left: '400px'
})
}
function shiftLetters() {
let start = performance.now();
let dist = -400;
let dur = 500;
const logoAnimate = (timestamp) => {
var runtime = timestamp - start
var progress = Math.min(runtime / dur, 1)
const position = progress * dist;
if (runtime < dur) {
for (let i = 0; i < pf.length; i++) {
(function(i) {
setTimeout(function() {
pf[i].style.transform = `translate3d(${position}px,0,0)`
}, 100 * i)
})(i);
}
requestAnimationFrame(logoAnimate)
}
}
requestAnimationFrame(logoAnimate)
}
document.getElementsByTagName('button')[0].addEventListener('click', shiftLetters);
#wrapper {
display: flex;
position: absolute;
-webkit-transform: translate(-50%, 10%);
transform: translate(-50%, 10%);
top: 50%;
left: 50%;
}
.pf {
display: inline-block;
position: relative;
width: 100px;
height: 100px;
margin: 2px;
background-color: red;
}
button {
display: block;
margin-top: 50px;
}
<div id="wrapper">
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
</div>
<button>animate</button>
I have 4 elements when button is clicked their supposed to end at the exact distance of the dist variable. Instead it end at random integers and never exactly -400px like stated in in my dist variable of -400. Has to be something simple. I've written the variables outside of scope etc etc..
The reason is that you never apply the final transform. On the last iteration of shiftLetters when position finally = -400 runtime is greater than dur so you never enter your if statement and apply the transform. Slightly refactored code below.
let pf = document.querySelectorAll('.pf');
for (let i of pf) {
Object.assign(i.style, {
left: '400px'
})
}
function shiftLetters() {
let start = performance.now();
let dist = -400;
let dur = 500;
const logoAnimate = (timestamp) => {
var runtime = timestamp - start
var progress = Math.min(runtime / dur, 1)
const position = progress * dist;
applyTransform(position);
if (runtime < dur) {
requestAnimationFrame(logoAnimate)
}
}
requestAnimationFrame(logoAnimate)
}
function applyTransform(position) {
for (let i = 0; i < pf.length; i++) {
setTimeout(function() {
pf[i].style.transform = `translate3d(${position}px,0,0)`
}, 100 * i)
}
}
document.getElementsByTagName('button')[0].addEventListener('click', shiftLetters);
#wrapper {
display: flex;
position: absolute;
-webkit-transform: translate(-50%, 10%);
transform: translate(-50%, 10%);
top: 50%;
left: 50%;
}
.pf {
display: inline-block;
position: relative;
width: 100px;
height: 100px;
margin: 2px;
background-color: red;
}
button {
display: block;
margin-top: 50px;
}
<div id="wrapper">
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
<div class="pf"></div>
</div>
<button>animate</button>

Make a splitter very thin and grab it

I want to make a draggle splitter between 2 panels. The following is a working version.
Now, I want to make the width of handle as thin as possible (less than 0.1px?), so there is no way to make the width (appear) smaller than 1px?
Additionally, when the splitter is thin, it is hard to select by the mouse. Is there a way to make a splitter easy to grab?
Taking JSBin as example, how did they manage to realise the splitters among the panels?
(function($) {
$.fn.drags = function(opt) {
opt = $.extend({
handle: "",
cursor: "ew-resize",
min: 10
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $el = this.find(opt.handle);
}
var priorCursor = $('body').css('cursor');
return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
priorCursor = $('body').css('cursor');
$('body').css('cursor', opt.cursor);
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
}
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
var mouseMove = function(e) {
var prev = $('.draggable').prev();
var next = $('.draggable').next();
var total = prev.outerWidth() + next.outerWidth();
var totalPercentage = parseFloat(prev.css('flex')) + parseFloat(next.css('flex'));
var offset = prev.offset();
if(offset){
var leftPercentage = ((e.pageX - offset.left - drg_w / 2) / total) * totalPercentage;
var rightPercentage = totalPercentage - leftPercentage;
if (leftPercentage * 100 < opt.min || rightPercentage * 100 < opt.min) {
return;
}
prev.css('flex', leftPercentage.toString());
next.css('flex', rightPercentage.toString());
}
}
$drag.css('z-index', 1000).parent().on("mousemove", mouseMove).on("mouseup", function() {
$(this).off("mousemove", mouseMove).off("mouseup");
$('body').css('cursor', priorCursor);
$('.draggable').removeClass('draggable').css('z-index', z_idx);
});
e.preventDefault(); // disable selection
});
}
})(jQuery);
$('.handle').drags();
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.handle {
width: 1px;
text-align: center;
background: grey;
transition: all ease-in 0.1s;
}
.draggable {
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex-box">
<div class="col">
<p>Pellentesque ...</p>
</div>
<div class="handle"></div>
<div class="col">
<p>Pellentesque ...</p>
</div>
</div>
If you'd like the handle to appear thinner try applying a negative value to the right "col" e.g. margin-left: -2px; so it overlaps the left "col" border on the left of it. I don't think you can make the width "appear" as 0.1px. Firefox is the only browser that renders such value. (https://css-tricks.com/forums/topic/0-1px-borders/)
.flex-box .col:last-child {
margin-left: -2px;
}
//raise handle layer to top
.handle {
.....
z-index: 9999;
}
Hope this helps...
*Edit:
This is the closest I could get to your request:
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.flex-box .col:last-child {
margin-left: -6px;
}
.handle {
width: 5px;
text-align: center;
transition: all ease-in 0.1s;
z-index: 999;
overflow: visible;
}
.handle-inner{
width: 5px;
height: 100%;
position: relative;
margin-left: -10px;
}
.draggable {
background: grey;
}
Jsbin :
https://jsbin.com/nupefekuhu/edit?html,css,js,output

How to fade in smoothly

I want to fade in div by clicking menu buttons.
I implemented it anyway but when I switch the views very quickly, it sometimes flashes and the behavior is kind of rough or jumpy..or I don't know how to say..it's not smooth anyways.
https://jsfiddle.net/eLbze55d/12/
Any advice would be appreciated.
var m_menu = document.getElementById('m_menu');
var menu = document.getElementById('menu');
var m_staff = document.getElementById('m_staff');
var staff = document.getElementById('staff');
var m_access = document.getElementById('m_access');
var access = document.getElementById('access');
m_menu.addEventListener('click', function() {
menu.style.zIndex = 1;
staff.style.zIndex = 0;
access.style.zIndex = 0;
menu.style.webkitAnimationName = 'fadein';
menu.style.webkitAnimationDuration = "1000ms";
});
menu.addEventListener('webkitAnimationEnd', function() {
menu.style.opacity = 1;
staff.style.opacity = 0;
access.style.opacity = 0;
menu.style.webkitAnimationName = '';
});
m_staff.addEventListener('click', function() {
staff.style.zIndex = 1;
menu.style.zIndex = 0;
access.style.zIndex = 0;
staff.style.webkitAnimationName = 'fadein';
staff.style.webkitAnimationDuration = "1000ms";
});
staff.addEventListener('webkitAnimationEnd', function() {
staff.style.opacity = 1;
menu.style.opacity = 0;
access.style.opacity = 0;
staff.style.webkitAnimationName = '';
});
m_access.addEventListener('click', function() {
access.style.zIndex = 1;
menu.style.zIndex = 0;
staff.style.zIndex = 0;
access.style.webkitAnimationName = 'fadein';
access.style.webkitAnimationDuration = "1000ms";
});
access.addEventListener('webkitAnimationEnd', function() {
access.style.opacity = 1;
menu.style.opacity = 0;
staff.style.opacity = 0;
access.style.webkitAnimationName = '';
});
#-webkit-keyframes fadein {
0% { opacity: 0; }
100% { opacity: 1; }
}
html,body { height:100%; }
#main {
height:100%;
color: white;
}
.content{
font-size: 50pt;
}
#menu {
z-index: 1;
opacity: 1;
position: absolute;
top: 0;
left: 0;
background-image: url(https://snap-photos.s3.amazonaws.com/img-thumbs/960w/7B62IKGVF4.jpg);
height: 100%;
width: 100%;
}
#staff {
z-index: 0;
opacity: 0;
position: absolute;
top: 0;
left: 0;
background-image: url(https://snap-photos.s3.amazonaws.com/img-thumbs/960w/FRHYAEUPIN.jpg);
height: 100%;
width: 100%;
}
#access{
z-index: 0;
position: absolute;
top: 0;
left: 0;
background-image: url(https://snap-photos.s3.amazonaws.com/img-thumbs/960w/MGWWJDK49D.jpg);
height: 100%;
width: 100%;
}
#site_menu {
z-index: 2;
position: absolute;
bottom: 2%;
left: 3.5%;
font-size: 20pt;
display: flex;
justify-content: start;
}
#site_menu > div {
cursor: pointer;
margin: 20px;
display: flex;
align-items: center;
justify-content: start;
}
<div id="main">
<div id="menu" class="content">THIS IS MENU</div>
<div id="staff" class="content">THIS IS STAFF</div>
<div id="access" class="content">THIS IS ACCESS</div>
<div id="site_menu">
<div id="m_menu" class="menuelem">Menu</div>
<div id="m_staff" class="menuelem">Staff</div>
<div id="m_access" class="menuelem">Access</div>
</div>
</div>

Categories