I've written this code. It rotates two divs like a card flip using css transform every 1000ms and displays new text in the div, which is drawn from an array. It runs infinitely.
But once the array reaches its end I get an 'undefined' value because the i++ is incrementing on the final array item. I have been going crazy trying to figure out how to prevent that. Any help?
Codepen: https://codepen.io/warpigs666/pen/OJpBKdy
<style>
#flip-card {
width: 100px;
height: 50px;
}
#flip-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
#textDiv1 {
background-color: lightblue;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
}
#textDiv2 {
background-color: lightcoral;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
transform: rotateX(180deg);
}
</style>
<body>
<div id="flip-card">
<div id="flip-card-inner">
<div id="textDiv1">
one
</div>
<div id="textDiv2">
set via script
</div>
</div>
</div>
<script>
var flipCard = document.getElementById('flip-card');
var flipCardInner = document.getElementById('flip-card-inner');
var textDiv1 = document.getElementById('textDiv1');
var textDiv2 = document.getElementById('textDiv2');
var wordArray = ["one", "two", "three", "four", "five"]
var i = 1;
function flipText(){
textDiv2.innerHTML = wordArray[i];
flipCardInner.style.transform = "rotateX(180deg)";
setTimeout(
function() {
textDiv1.innerHTML = wordArray[i++];
flipCardInner.style.transform = "rotateX(360deg)";
}, 1000
);
if (i<wordArray.length){
i++;
}
else {i=0;}
}
var flipIt = setInterval(flipText, 2000);
</script>
</body>
This is a job for setInterval
var flipCard = document.getElementById('flip-card');
let flipCardInner = document.getElementById('flip-card-inner');
let textDiv1 = document.getElementById('textDiv1');
let textDiv2 = document.getElementById('textDiv2');
let wordArray = ["one", "two", "three", "four", "five"];
let i = 0;
let timerVal = 1000;
function getI(i) {
if (i < wordArray.length - 1) return i + 1;
else return 0;
}
let ctr = 1,
useDiv; // ctr and useDiv will help to toggle between divs in our loop and also increment the transform number
textDiv1.innerHTML = wordArray[i]; // initialize
function flipText() {
i = getI(i);
useDiv = (useDiv == textDiv2) ? textDiv1 : textDiv2;
useDiv.innerHTML = wordArray[i];
flipCardInner.style.transform = "rotateX(" + (ctr * 180) + "deg)";
ctr++;
}
let interval
window.onload = function() {
// we'll still delay the beginning of the infinite loop, but then we set it to an interval, so it runs forever.
// if you need to stop it in your code, just use clearInterval(interval)
setTimeout(() => {
interval = setInterval(() => flipText(), timerVal);
}, timerVal);
}
#flip-card {
width: 100px;
height: 50px;
perspective: 100px;
}
#flip-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
#textDiv1 {
background-color: lightblue;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
}
#textDiv2 {
background-color: lightcoral;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
transform: rotateX(180deg);
}
<div id="flip-card">
<div id="flip-card-inner">
<div id="textDiv1">
</div>
<div id="textDiv2">
</div>
</div>
</div>
The issue is as follows, you are incrementing i twice, when it should just be one time:
function() {
textDiv1.innerHTML = wordArray[i++]; ==> Here
flipCardInner.style.transform = "rotateX(360deg)";
}, 1000
);
if (i<wordArray.length){
i++; ==> And here
}
else {i=0;}
}
remove the increment on wordArray[i++], should not give you error.
Also make it i < wordArray.length -1
I don't think this is the ideal way of this job but sticking to your context perhaps like this;
var flipCard = document.getElementById('flip-card'),
flipCardInner = document.getElementById('flip-card-inner'),
textDiv1 = document.getElementById('textDiv1'),
textDiv2 = document.getElementById('textDiv2'),
wordArray = ["one", "two", "three", "four", "five"],
i = 0;
function flipText(){
textDiv2.innerHTML = wordArray[++i % wordArray.length];
flipCardInner.style.transform = "rotateX(180deg)";
setTimeout(function(){
textDiv1.innerHTML = wordArray[++i % wordArray.length];
flipCardInner.style.transform = "rotateX(360deg)";
}, 1000);
}
var flipIt = setInterval(flipText, 2000);
#flip-card { width: 100px;
height: 50px;
}
#flip-card-inner { position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
#textDiv1 { background-color: lightblue;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
}
#textDiv2 { background-color: lightcoral;
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
text-align: center;
transform: rotateX(180deg);
}
<div id="flip-card">
<div id="flip-card-inner">
<div id="textDiv1">
one
</div>
<div id="textDiv2">
set via script
</div>
</div>
</div>
Related
I am trying to make connect4 HTML game and I know I will be better off using canvas elements instead of a grids of divs but is it possible to make transition translate type of css animation when moving HTML elements around like this (using appendChild)
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if(rowNum==1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
})
#main {
left:100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>
Click on the red dot to toggle position of ball
You can use animationend to check when the animation end and move the ball element between the divs
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener('animationend', () => {
ball.classList.remove("animate-ball");
ball.style.animation = "";
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
});
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
ball.style.animation = "MoveDown 1s linear";
} else {
ball.style.animation = "MoveUp 1s linear";
}
ball.classList.add("animate-ball");
})
#main {
left: 100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
position: relative;
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
.animate-ball {
animation-iteration-count: 1;
position: absolute;
bottom: 0;
}
#keyframes MoveUp {
0% {
top: -50px;
}
100% {
top: -100px;
}
}
#keyframes MoveDown {
0% {
top: 0;
}
100% {
top: 50px;
}
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>
I'm trying to convert the product-page tabs to an accordion on my Woocommerce store, but things won't work. When i click on my links, the dropdown doesn't show, it doesn't do nothing ... The height should animate as well as my "+" icon, but nothing happens. It looks like it doens't wnat to add the "is-open" class on the clicked element. So i think my error lies in my js, but i don't see where!
Here's my tabs.php file :
<?php
/**
* Single Product tabs
*
* This template can be overridden by copying it to yourtheme/woocommerce/single-product/tabs/tabs.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce\Templates
* #version 3.8.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Filter tabs and allow third parties to add their own.
*
* Each tab is an array containing title, callback and priority.
*
* #see woocommerce_default_product_tabs()
*/
$product_tabs = apply_filters('woocommerce_product_tabs', array());
if (!empty($product_tabs)) : ?>
<div class="c-accordion">
<div class="c-accordion__wrapper">
<div class="c-accordion__content-wrapper">
<?php foreach ($product_tabs as $key => $product_tab) : ?>
<div class="c-accordion__content js-accordion">
<div class="c-accordion__content-title">
<span class="c-accordion__plus"></span>
<p class="u-a1">
<?php echo wp_kses_post(apply_filters('woocommerce_product_' . $key . '_tab_title', $product_tab['title'], $key)); ?>
</p>
</div>
<div class="c-accordion__content-main js-content">
<?php
if (isset($product_tab['callback'])) {
call_user_func($product_tab['callback'], $key, $product_tab);
}
?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
Here's my js :
// Custom Tabs
('use strict');
var Accordion = /** #class */ (function () {
function Accordion() {
this.items = document.querySelectorAll('.js-accordion');
this.itemClass = '.js-accordion';
this.contentWrapperClass = '.js-content';
this.css = {
open: 'is-open',
};
if (this.items.length > 0) {
this.init();
}
}
Accordion.prototype.init = function () {
var _this = this;
for (var i = 0; i < this.items.length; i++) {
this.items[i].addEventListener('click', function (ev) {
ev.preventDefault();
var current = ev.currentTarget;
var contentWrapper = current.querySelector(_this.contentWrapperClass);
if (!current.classList.contains(_this.css['open'])) {
_this.slideDown(current, contentWrapper);
return;
}
_this.closeItem();
});
}
};
Accordion.prototype.getActiveElement = function () {
var accordionItems = document.querySelectorAll('' + this.itemClass);
var active = null;
for (var i = 0; i < accordionItems.length; i++) {
if (accordionItems[i].classList.contains(this.css['open'])) {
active = accordionItems[i];
}
}
return active;
};
Accordion.prototype.slideDown = function (element, content) {
var _this = this;
var contentHeight = 0;
var active = this.getActiveElement();
for (var i = 0; i < this.items.length; i++) {
this.items[i].classList.remove(this.css['open']);
}
element.classList.add(this.css['open']);
if (active) {
var activeContent = active.querySelector(this.contentWrapperClass);
TweenMax.to(activeContent, 0.6, {
height: 0,
onStart: function () {
_this.openItem(content, contentHeight);
},
});
return;
}
// else
this.openItem(content, contentHeight);
};
Accordion.prototype.openItem = function (content, contentHeight) {
TweenMax.set(content, {
height: 'auto',
onComplete: function () {
contentHeight = content.clientHeight;
TweenMax.set(content, {
height: 0,
onComplete: function () {
TweenMax.to(content, 0.4, {
height: contentHeight,
onComplete: function () {
TweenMax.set(content, {
height: 'auto',
});
},
});
},
});
},
});
};
Accordion.prototype.closeItem = function () {
var active = this.getActiveElement();
if (active) {
var activeContent = active.querySelector(this.contentWrapperClass);
active.classList.remove(this.css['open']);
TweenMax.to(activeContent, 0.6, {
height: 0,
});
}
};
return Accordion;
})();
new Accordion();
and here's my css (scss) :
.c-accordion {
max-width: 100%;
width: 100%;
font-family: helvetica;
&__wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
height: auto;
}
&__content-wrapper {
flex: 1 0 100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
align-content: stretch;
}
&__content-title {
position: relative;
transition: 0.3s;
padding-top: 10px;
padding-bottom: 10px;
padding-left: percentage(1/15);
}
&__content-main {
height: 0;
overflow: hidden;
padding-left: percentage(1/15);
display: flex;
flex-wrap: wrap;
p {
max-width: 300px;
}
}
&__content {
position: relative;
overflow: hidden;
cursor: pointer;
flex: 1 0 auto;
&:first-of-type {
&:before {
display: none;
}
}
&:before {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
left: 0;
top: 0;
}
&:last-child {
&:after {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
left: 0;
bottom: 0;
}
}
&__text {
padding-top: 10px;
padding-bottom: 20px;
line-height: 1.38;
}
&:hover {}
&.is-open {
transition: 0.3s;
.c-accordion {
&__plus {
transform: translateY(-50%) rotate(90deg);
&:after {
opacity: 0;
}
}
&__content-main {
height: auto;
}
}
}
}
&__plus {
width: 3vh;
height: 3vh;
position: absolute;
left: 0px;
top: 50%;
cursor: pointer;
opacity: 1;
transform: translateY(-50%) rotate(0deg);
transition: 0.4s;
&:before {
content: '';
height: 100%;
border-left: 2px solid $black;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
opacity: 1;
}
&:after {
content: '';
width: 100%;
border-top: 2px solid $black;
position: absolute;
opacity: 1;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.2s;
}
}
&__left {
padding-top: 10px;
padding-bottom: 75px;
width: percentage(6/14);
padding-right: 10px;
}
&__right {
padding-top: 10px;
padding-bottom: 75px;
width: percentage(8/14);
padding-right: 10px;
}
}
Does someone have any idea what i'm doing wrong ?
Thanks a lot !
Fixed, the error wasn't with this JS but there was a conflict with another plugin. Solved
So I am trying to get the script to display a certain amount of css black squares, when a number is entered in the prompt, I really have no Idea how to approach this here is my code so far
<!DOCTYPE html>
<html>
<head>
<style>
.square {
width: 100px;
height: 100px;
background-color: black;
}
</style>
<div class="square">
</div>
</head>
<body>
<script>
var msg = prompt('How Many squares?');
</script>
</body>
</html>
I started reading about loops, as I thought that might be what i needed to do. but I don't understand them just yet.
let msg = parseInt(prompt('How Many squares?')); //need to convert the input to number as it's always a string
if(msg > 0){
let body = document.querySelector('body'); //selector for where you want the elements to go
let element = `
<div class="square"></div>
`; //html string
for (let i = 0; i < msg - 1; i++) { //I like starting loops from 0 so need to subtract 1 from msg
body.insertAdjacentHTML('afterBegin', element); //insert the html element inside the selector
}
}
const squre_container = document.getElementById('square-container');
var inp = parseInt(prompt('how many squres do you want', 5));
for(let i=0; i<inp; i++){
let sq = document.createElement('div');
sq.setAttribute('class', 'square');
squre_container.appendChild(sq);
}
.square {
width: 100px;
height: 100px;
background-color: black;
}
#square-container{
width: 100vw;
height: 100vh;
}
<div id='square-container'></div>
I wish you delete this question, SO is for programming specific issue, instead of tutorial guild. Without using positioning such as grid and flexbox, the code ends up stuck together. This post does not directly answer your question, but provides high-quality learning resource, click on the black box then the other boxes to see what happens.
const available_container = document.getElementById('available-container');
const using_container = document.getElementById('using-container');
const switch_available = document.getElementById('available-panel-app');
let available_state = true;
let available_amount = 3;
let using_amount = 2;
available_gtc = Math.ceil(Math.sqrt(available_amount));
let frs = Array.from(Array(available_gtc), ()=>'1fr').join(' ');
available_container.style.gridTemplateColumns = frs;
available_container.style.gridTemplateRows = frs;
using_container.style.gridTemplateColumns = '1fr';
for (let i = 0; i < available_amount; i++){
let app = document.createElement('div');
app.setAttribute('class', 'available-app');
available_container.appendChild(app);
}
for (let i = 0; i < using_amount; i++){
let app = document.createElement('div');
app.setAttribute('class', 'using-app');
using_container.appendChild(app);
}
const available_apps = document.querySelectorAll('.available-app');
const using_apps = document.querySelectorAll('.using-app');
const random_color = () => '#'+(Math.random() * 0xFFFFFF << 0).toString(16).padStart(6, '0');
function available_category(app){
app.addEventListener('click', ()=>{
if(available_state){return;}
app.classList.add('vanish');
setTimeout(()=>{
app.classList.remove('available-app');
app.classList.add('using-app');
using_container.appendChild(app);
app.classList.remove('vanish');
app.classList.add('matter');
setTimeout(()=>{
app.classList.remove('matter');
}, 1000);
}, 1000);
using_category(app);
});
}
function using_category(app){
app.addEventListener('click', ()=>{
if(available_state){return;}
app.classList.add('vanish');
setTimeout(()=>{
app.classList.remove('using-app');
app.classList.add('available-app');
available_container.appendChild(app);
app.classList.remove('vanish');
app.classList.add('matter');
setTimeout(()=>{
app.classList.remove('matter');
}, 1000);
}, 1000);
available_category(app);
});
}
// color
available_apps.forEach(app=>{
app.style.backgroundColor = random_color();
available_category(app);
});
using_apps.forEach(app=>{
app.style.backgroundColor = random_color();
using_category(app);
});
switch_available.addEventListener('click', ()=>{
if(available_state){
available_container.style.display = 'grid';
available_container.classList.add('matter');
setTimeout(()=>{
available_container.classList.remove('matter');
}, 1000);
}else{
available_container.classList.add('vanish');
setTimeout(()=>{
available_container.classList.remove('vanish');
available_container.style.display = 'none';
}, 1000);
}
available_state = !available_state;
});
#available-container{
position: fixed;
border: 1px solid;
width: calc(95vw - 100px);
height: 100vh;
}
#using-container{
position: fixed;
right: 0;
border: 1px solid;
width: 100px;
height: 100vh;
}
/*flexbox*/
#available-container{
display: none;
overflow: hidden;
}
#using-container{
display: grid;
overflow: hidden;
}
#available-panel-app{
background-color: black;
width: 5rem;
height: 5rem;
}
.available-app{
width: 8rem;
height: 8rem;
}
.using-app{
width: 5rem;
height: 5rem;
}
.vanish{
opacity: 0;
transition: opacity 1s;
animation: disappear 1s;
}
.matter{
opacity: 1;
transition: opacity 1s;
animation: appear 1s;
}
#keyframes appear{
0%{
transform: scale(.1);
opacity: 0;
border-radius: 100%;
}
100%{
transform: scale(1);
opacity: 1;
border-radius: 0;
}
}
#keyframes disappear{
0%{
transform: scale(1);
opacity: 1;
border-radius: 0;
}
100%{
transform: scale(.1);
opacity: 0;
border-radius: 100%;
}
}
<div id="available-container">
</div>
<div id='using-container'>
<div id='available-panel-app'></div>
</div>
I am creating a little game that should be like a 2d version of "guitar hero" (if you don't know what "guitar hero" is don't worry, it was just to give context). I have a red square creator function called squareCreator that adds each new square created a CSS class of .newMostLeftNote. Afterward, I want each one of those squares to fall down (like gravity) using the function fallingMostLeftNote. The problem is that the margin-top that function adds to the square generated by the squareCreator adds to every single square at the same time (even before the square is created), so a square could be created when the .newMostLeftNote CSS class has a margin-top of 700 and it appears way at the bottom.
How can I make it so that every square that falls, but starts falling after they appear?
Notice that in this image, every margin-top CSS property for every new generated square is exactly the same.
var mostLeftNoteMarginTop = 0;
function squareCreator(){
var newNote = document.createElement("div");
newNote.className = "newMostLeftNote";
document.body.appendChild(newNote);
}
var generationSpeed = setInterval(squareCreator, 300);
function fallingMostLeftNote() {
mostLeftNoteMarginTop += 2;
$(".newMostLeftNote").css({
'margin-top': mostLeftNoteMarginTop + 'px'
});
}
proc = setInterval(fallingMostLeftNote, 5);
.newMostLeftNote {
height: 100px;
width: 100px;
background-color: red;
margin-left: 400px;
position: absolute;
}
.mostLeftNote {
height: 100px;
width: 100px;
background-color: red;
margin-left: 300px;
position: absolute;
}
.middleNote {
height: 100px;
width: 100px;
background-color: blue;
margin-left: 600px;
position: absolute;
}
.mostRightNote {
height: 100px;
width: 100px;
background-color: green;
margin-left: 900px;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Score: 0</h1>
<div class="middleNote"></div>
<div class="mostLeftNote"></div>
<div class="mostRightNote"></div>
<div class="scoreLineTop"></div>
<div class="scoreLineButtom"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="main.js" charset="utf-8"></script>
</body>
Update
var squareQuantity = [];
function squareCreator(){
var newNote = document.createElement("div");
newNote.className = "newMostLeftNote";
document.body.appendChild(newNote);
squareQuantity.push(this.newNote);
}
var generationSpeed = setInterval(squareCreator, 300);
function fallingMostLeftNote() {
mostLeftNoteMarginTop += 2;
squareQuantity[2].css({
'margin-top': mostLeftNoteMarginTop + 'px'
});
}
Instead of using javascript to update your margin-top, you could use CSS animations. Each new square will animate independently.
Here's an example for your use case:
function addSquare() {
var squaresElement = document.getElementById("squares");
var squareElement = document.createElement("div");
squareElement.className = "square";
squaresElement.append(squareElement);
}
#squares {
display: flex;
}
.square {
height: 100px;
width: 100px;
margin-right: 10px;
background-color: red;
animation-name: fall;
animation-duration: 4s;
animation-timing-function: linear;
}
/* The animation code */
#keyframes fall {
from {margin-top: 0px;}
to {margin-top: 300px;}
}
<button onclick="addSquare()">Add square</button>
<div id="squares"></div>
My approach is giving a css variable while creating divs for transform delay. If you need more complex movements, you can use the same logic for animation instead of transform.
<div class="parent"></div>
.parent {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.lets-try {
flex: 1;
background: #000;
height: 60px;
margin-right: 5px;
margin-left: 5px;
transition: all 0.5s ease-in-out var(--delay);
}
.lets-try.is-falling {
margin-top: 100px;
}
let parent = document.querySelector(".parent");
let numOfSquares = 12;
for (let i = 0; i < numOfSquares ; i++) {
let delay = i * 0.2;
let div = document.createElement('div');
div.setAttribute('class', 'lets-try');
div.setAttribute('style', `--delay:${delay}s`);
parent.appendChild(div);
}
setTimeout(() => {
let items = document.querySelectorAll(".lets-try");
[...items].forEach(item => {
item.classList.add("is-falling")
})
}, 1)
I try to build a Slideshow in JS + CSS and it works pretty well except one visual glitch. The Transition to the last slides seems somehow broken.
But I couldn't figure out what the problem is. If I comment out the "offset" transition on the last slide, the error doesn't occure.
This is the codeine I am talking about: https://codepen.io/marianbreitmeyer/pen/paeYgZ
The Block of code I mentioned is this one:
const showNext = function() {
clicked = true;
for (i = 0; i <= slides.length-1; i++) {
if( parseInt(slides[i].style.zIndex) === slides.length) {
console.log(slides[i].innerHTML);
triggerAnimation(slides[i], 'offcanvas');
} else if (parseInt(slides[i].style.zIndex) === slides.length-1) {
//the line below triggers the problem
triggerAnimation(slides[i], 'offset');
}
}
};
Maybe someone with more experience could help me :)
Your code might be more simple:
const btn = document.getElementsByClassName('arrow')[0];
const slides = document.getElementsByClassName('slide');
slides[slides.length - 1].classList.add('offset', 'next');
btn.addEventListener("click", function(e) {
var o, n;
for (var i = 0; i < slides.length; i++) {
if (slides[i].classList.contains('offset')) {
slides[i].classList.remove('offset', 'next')
slides[i].classList.add('offcanvas');
o = (slides[i - 1] || slides[slides.length - 1]);
n = (slides[i - 2] || slides[slides.length + i - 2]);
}
if (slides[i].offsetLeft < -slides[i].offsetWidth) {
slides[i].classList.remove('offcanvas', 'next');
}
}
o.classList.add('offset');
n.classList.add('next');
}, false);
.container {
width: 100%;
height: 100vh;
background: brown;
position: relative;
}
body {
text-align: center;
font-size: 2rem;
}
.slide {
position: absolute;
top: 0;
left: 90%;
width: 100%;
height: 100%;
}
.slide:nth-child(1) {
background: pink;
}
.slide:nth-child(2) {
background: blue;
}
.slide:nth-child(3) {
background: green;
}
.slide:nth-child(4) {
background: grey;
}
.slide:nth-child(5) {
background: yellow;
}
.slide.next {z-index:1}
.slide.offset {
left: -10%;
z-index: 2;
transition: left .65s ease-in-out;
}
.slide.offcanvas {
left: -110%;
z-index: 2;
transition: left .65s ease-in-out;
}
.arrow {
position: absolute;
right: 5%;
top: 25px;
z-index: 9;
height: 50px;
width: 50px;
cursor: pointer;
}
.arrow:hover path {
transform: translate(16px, 0px);
}
path {
position: absolute;
top: 0;
left: 0;
transition: all .2s ease-in-out;
}
<div class="container">
<div class="slide">1 = pink</div>
<div class="slide">2 = blue</div>
<div class="slide">3 = green</div>
<div class="slide">4 = grey</div>
<div class="slide">5 = yellow</div>
<svg xmlns="http://www.w3.org/2000/svg" class="arrow"><path d="M19.443 5.17L30.138 15.5H-.095v1h30.233L19.443 26.829l.696.719L32.095 16 20.139 4.451z"/></svg>
</div>