I've built a pretty basic HTML/CSS/JS slideshow. When I click the button on the right, the slide switches to the next slide, and when I click the button on the left, the slide switches to the previous slide.
However, I would like to add in a scrolling animation to make the slideshow feel less rigid; when I press the button on the right, I want the slide to 'slide' in from the right, and when I press the button on the left I want it to slide in from the left.
I've been researching possible ways to do this and came across CSS animations, specifically the w3.css framework (https://www.w3schools.com/w3css/w3css_animate.asp), but am not sure how I would implement this given that my slideshow already makes use of classes in order to switch between slides.
Here is my code:
var content = ["Slide 1", "Slide 2", "Slide 3"];
var style = ["background-color: blue;", "background-color: red;", "background-color: green;"];
var index = 0;
function next() {
if (index == (content.length - 1)) {
index = 0
} else {
index = index + 1
}
document.getElementById("slide").innerHTML = content[index];
document.getElementById("slideshow").style = style[index];
}
function back() {
if (index == 0) {
index = (content.length - 1)
} else {
index = index - 1
}
document.getElementById("slide").innerHTML = content[index];
document.getElementById("slideshow").style = style[index];
}
.slideshow {
position: relative;
height: 170px;
color: white;
background-color: blue;
}
.slideshow p {
position: absolute;
width: 100%;
margin-top: 0;
margin-bottom: 0;
text-align: center;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
}
.slideshow button {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 25px;
}
<!DOCTYPE html>
<html lang="en">
<body>
<div class="slideshow" id="slideshow">
<p id="slide">Slide 1</p>
<button onclick="back()" style="left: 0">❮</button>
<button onclick="next()" style="right: 0">❯</button>
</div>
</body>
</html>
Thanks in advance.
you can style a next and prev classes with CSS and then toggle them with js like this snippet
var content = ["Slide 1", "Slide 2", "Slide 3"];
var style = ["background-color: blue;", "background-color: red;", "background-color: green;"];
var index = 0;
function next() {
const slide = document.getElementById("slide");
if (index == (content.length - 1)) {
index = 0;
} else {
index = index + 1;
}
// wipe out class
slide.className = '';
// add next class
setTimeout(() => slide.classList.add('next'), 0);
slide.innerHTML = content[index];
slide.style = style[index];
}
function back() {
const slide = document.getElementById("slide");
if (index == 0) {
index = (content.length - 1);
} else {
index = index - 1;
}
// wipe out class
slide.className = '';
// add prev class
setTimeout(() => slide.classList.add('prev'), 0);
slide.innerHTML = content[index];
slide.style = style[index];
}
.slideshow {
position: relative;
height: 170px;
color: white;
overflow: hidden;
}
.slideshow p {
position: absolute;
width: 100%;
height: 100%;
line-height: 170px;
margin-top: 0;
margin-bottom: 0;
text-align: center;
top: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
background-color: blue;
}
.slideshow button {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 25px;
}
.prev {
animation: prev 1s ease-in-out forwards;
}
.next {
animation: next 1s ease-in-out forwards;
}
#keyframes prev {
from {
left: -150%;
}
to {
left: 50%;
}
}
#keyframes next {
from {
right: -150%;
}
to {
right: -50%;
}
}
<div class="slideshow" id="slideshow">
<p id="slide" class="next">Slide 1</p>
<button onclick="back()" style="left: 0">❮</button>
<button onclick="next()" style="right: 0">❯</button>
</div>
Related
I am pretty new here and also with Javascript but I have tried for quite some time now and can't get my head around how to have individual data in a popup image gallery.
I have tried adding it in multiple ways, and I do not really need a number (1-..) but an individual URL, also an individual description (using the alt tag). So this is the first code that offered it to me and I hope there is some geeks in this community that can give me an easy and quick "fix".
Many thanks in advance!
Here is some code to make you understand better (hopefully):
HTML:
<div class="popup">
<!-- top bar -->
<div class="top-bar">
<p class="image-name">img1.png</p>
<p class="image-description">Just an image</p>
<span class="close-btn"></span>
!-- image -->
<img src="./img/ads/1.png" class="large-image" alt="Just an image">
<!-- image-index -->
<p class="index">01</p>
</div>
<div class="gallery">
<div class="gallery-image">
<img src="./img/ads/1.png" alt="Just an image" class="image">
</div>...
CSS:
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
width: 80%;
max-width: 100%;
height: 90vh;
max-height: 70%;
border-radius: 20px;
background: rgba(0, 0, 0, 0.75);
display: flex;
justify-content: center;
align-items: center;
z-index: 5;
overflow: hidden;
transition: 1s;
opacity: 0;
}
.popup.active {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
.popup.active .close-btn,
.popup.active .image-name,
.popup.active .index,
.popup.active .image-description,
.popup.active .large-image,
.popup.active .arrow-btn {
opacity: 1;
transition: opacity .5s;
transition-delay: 1s;
}
.top-bar {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50px;
background: #000;
color: #fff;
text-align: center;
line-height: 50px;
font-weight: 300;
}
.image-name {
opacity: 0;
}
.close-btn {
opacity: 0;
position: absolute;
top: 15px;
right: 20px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #f00;
cursor: pointer;
}
JAVASCRIPT:
const popup = document.querySelector('.popup');
const closeBtn = document.querySelector('.close-btn');
const imageName = document.querySelector('.image-name');
const largeImage = document.querySelector('.large-image');
const imageDis = document.querySelector('.image-description');
const imageIndex = document.querySelector('.index');
const leftArrow = document.querySelector('.left-arrow');
const rightArrow = document.querySelector('.right-arrow');
let index = 0; // will track our current image;
images.forEach((item, i) => {
item.addEventListener('click', () => {
updateImage(i);
popup.classList.toggle('active');
});
});
const updateImage = i => {
let path = `./img/ads/${i + 1}.png`;
largeImage.src = path;
imageName.innerHTML = path;
imageIndex.innerHTML = `0${i + 1}`;
index = i;
};
closeBtn.addEventListener('click', () => {
popup.classList.toggle('active');
});
leftArrow.addEventListener('click', () => {
if (index > 0) {
updateImage(index - 1);
}
});
rightArrow.addEventListener('click', () => {
if (index < images.length - 1) { updateImage(index + 1); } });```
I built a carousel for some images. I need my 'next' and 'previous' buttons to use the CSS animation that I assigned them in my javascript function for their event listeners.The animation will only play for one click, and when the buttons are clicked again to navigate the carousel the animation doesn't play. I need the buttons to grow and shrink for every click.
Here's the CSS:
.carousel-actions {
position: absolute;
display: flex;
justify-content: space-between;
width: 105%;
top: 30%;
}
.carousel-actions button {
padding: 30px 50px;
background-color: rgba(255, 255, 255, 0.329);
font-weight: 900;
cursor: pointer;
border-radius: 100px;
border: 0;
font-size: 60px;
color: black;
outline: none;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
Here's the HTML:
<div class="carousel-actions">
<button id="prev" aria-label="Previous Slide"><</button>
<button id="next" aria-label="Next Slide">></button>
</div>
Here's the JS:
const slides = document.querySelectorAll(".carousel-item");
const totalSlides = slides.length;
let slidePosition = 0;
console.log(totalSlides);
const next = document.getElementById("next");
const prev = document.getElementById("prev");
function hideAllSlides() {
for (const slide of slides) {
slide.classList.remove("carousel-item-visible") &&
slide.classList.add("carousel-item-hidden");
}
}
function nextSlide() {
hideAllSlides();
if (slidePosition === totalSlides - 1) {
slidePosition = 0;
} else {
slidePosition++;
}
slides[slidePosition].classList.add("carousel-item-visible");
next.style.animation = "grow 1s";
}
function prevSlide() {
hideAllSlides();
if (slidePosition === 0) {
slidePosition = totalSlides - 1;
} else {
slidePosition--;
}
slides[slidePosition].classList.add("carousel-item-visible");
prev.style.animation = "grow 1s";
}
next.addEventListener("click", nextSlide);
prev.addEventListener("click", prevSlide);
The problem is seen because once the system has played the animation it thinks 'well, I've played it'. Setting it to the same again does not make it play again.
To get round this you can unset the animation when it has finished.
In your code add an event listener for the animationend event.
Here's a simplified example:
const div = document.querySelector('div');
div.addEventListener('click', function() { div.style.animationName='grow';});
div.addEventListener('animationend', function() { div.style.animationName='';});
div {
width: 100px;
height: 100px;
background-color: blue;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
<div></div>
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 have a web page where I am using a sticky button to use only on mobile
<div id="toBooking" class="bg-light d-lg-none d-xl-none">
<a class="btn_full" style="margin-bottom:0; background: #0072bc !important;" href="#"> <sup>$</sup> Book Now</a>
</div>
Here is the javascript that I have
var pxBtShow = 500; // height on which the button will show
var scrollSpeed = 500; // how slow / fast you want the button to scroll to top.
$(window).scroll(function(){
if($(window).scrollTop() >= pxBtShow){
$("#toBooking").addClass('visible');
} else {
$("#toBooking").removeClass('visible');
}
});
$("#toBooking").click(function() {
$('html, body').animate({
scrollTop: $("#booking").offset().top
}, 1000);
});
and CSS
#toBooking {
position: fixed;
right: 0;
opacity: 0;
visibility: hidden;
bottom: 0px;
z-index: 999;
transition: 0.35s;
transform: scale(0.7);
width: 100%;
height: 46px;
background-color: rgba(0,0,0,.6);
opacity: 1;
transition: all 0.3s;
border-radius: 50%;
text-align: center;
font-size: 21px;
color: #fff;
cursor: pointer;
}
#toBooking.visible {
opacity: 1;
visibility: visible;
transform: scale(1);
}
#toBooking:after {
content: "\e899";
font-family: "fontello";
position: relative;
display: block;
top: 50%;
-webkit-transform: translateY(-55%);
transform: translateY(-55%);
}
When I click the button it takes me to a booking form. But when I am on the form I want to hide that button during the height of that form.
How we can do that?
You just need to add more logic ex:
$(window).scroll(function () {
var windowScrollTop = $(window).scrollTop()
var $form = $('#form');
var formOffset = $form.offset();
if (
windowScrollTop >= pxBtShow &&
windowScrollTop < formOffset.top &&
windowScrollTop > formOffset.top + $form.height()
) {
$("#toBooking").addClass('visible');
} else {
$("#toBooking").removeClass('visible');
}
});
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>