How can I make the 2nd image(the bottom) stay in place till the 1st image(the active) completely finish transition in place? and then start the loop again without reordering the array? I don't know if this is completely wrong or if I'm missing something, I've been trying for a while! please explain your comment/answer, thanks for helping.
var slideIndex = 0;
carousel();
function carousel() {
var i;
var slideShowSlide = document.querySelector('.slideshow__slide');
var slideBgFigure = Array.from(slideShowSlide.children);
var slideWidth = slideBgFigure[0].getBoundingClientRect().width;
for (i = 0; i < slideBgFigure.length; i++) {
slideBgFigure[i].style.transform = "translateX(-" + slideWidth + "px)";
}
slideIndex++;
if (slideIndex > slideBgFigure.length) {
slideIndex = 1;
}
slideBgFigure[slideIndex - 1].style.transform = "translateX(0px)";
setTimeout(carousel, 3000);
};
.slideshow__slide {
overflow: hidden;
height: 359px;
position: relative;
}
.slide__bg {
position: absolute;
width: 100%;
margin: 0;
color: #fff;
background: #333;
overflow-x: hidden;
-webkit-box-shadow: inset 0 0 0 1px #f0f0f0;
box-shadow: inset 0 0 0 1px #f0f0f0;
transition: all 1.5s ease;
}
.slide__bg img {
display: block;
}
<section class="slideshow__slide slide">
<figure class="slide__bg current">
<img src="https://via.placeholder.com/620x200/070" />
</figure>
<figure class="slide__bg">
<img src="https://via.placeholder.com/620x200/700" />
</figure>
<figure class="slide__bg">
<img src="https://via.placeholder.com/620x200/007" />
</figure>
</section>
I don't know why this question got 2 downvotes? Maybe it wasted people's time? It wasted my whole morning too, damn...
Here might be what the OP wants to get. I used CSS animation to control animation instead of javascript, setInterval instead of setTimeout. I use javascript to control which slide whose the class current. But it turned out the most tricky time-consuming part of me is not animation, but z-index. I got a typo and it messed up too. Holy damn, took a lot of time to do this looks easy problem.
Edit: The simpler code, use CSS transition instead of animation, the javascript code just permutate the classes.
var slideShowSlide = document.querySelector('.slideshow__slide');
var slideBgFigure = Array.from(slideShowSlide.children);
function permutateClassname(array) {
var tmp = array[0].className;
for (let i = 0; i < array.length - 1; i++) {
array[i].className = array[i + 1].className;
}
array[array.length - 1].className = tmp;
}
function carousel() {
permutateClassname(slideBgFigure);
}
setInterval(carousel, 3000);
.slideshow__slide {
overflow: hidden;
height: 359px;
position: relative;
}
.slide__bg {
position: absolute;
width: 100%;
margin: 0;
color: #fff;
background: #333;
overflow-x: hidden;
-webkit-box-shadow: inset 0 0 0 1px #f0f0f0;
box-shadow: inset 0 0 0 1px #f0f0f0;
}
.slide__bg img {
display: block;
opacity: .3;
}
.slide__bg {
transition: transform 1.5s ease-in;
}
.slide__bg.slide-out {
transform: translateX(-100%);
z-index: 0;
}
.slide__bg.slide-in {
transform: translateX(0);
z-index: 2;
}
.slide__bg.middle {
transform: translateX(0);
z-index: 1;
}
<section class="slideshow__slide slide">
<figure class="slide__bg slide-out">
<img src="https://via.placeholder.com/620x200/070" />
</figure>
<figure class="slide__bg slide-in">
<img src="https://via.placeholder.com/620x200/700" />
</figure>
<figure class="slide__bg middle">
<img src="https://via.placeholder.com/620x200/007" />
</figure>
</section>
Useful link: https://css-tricks.com/controlling-css-animations-transitions-javascript/
Related
I am currently building a website and I want a aesthetically pleasing landing page with a background fade in and out slideshow comprised of pictures that repeat y and x. I have the fading slideshow working perfectly and all I need is to repeat the image across the screen. Adding background: repeat to the CSS does not work. Below is may code:
HTML:
<div class="mybody" id="slider">
<div>
<h2>Dog Adoption</h2>
<p>Find the perfect match for your new four legged companion</p>
</div>
</div>
JavaScript:
var curIndex = 0,
imgDuration = 3000,
slider = document.getElementById("slider"),
slides = slider.childNodes; //get a hook on all child elements, this is live so anything we add will get listed
imgArray = [
'../../static/main/images/slideshow/dog2.jpg',
'../../static/main/images/slideshow/dog3.jpg',
'../../static/main/images/slideshow/dog4.jpg',
'../../static/main/images/slideshow/dog1.jpg',
];
//
// Dynamically add each image frame into the dom;
//
function buildSlideShow(arr) {
for (i = 0; i < arr.length; i++) {
var img = document.createElement('img');
img.src = arr[i];
slider.appendChild(img);
}
// note the slides reference will now contain the images so we can access them
}
//
// Our slideshow function, we can call this and it flips the image instantly, once it is
called it will roll
// our images at given interval [imgDuration];
//
function slideShow() {
function fadeIn(e) {
e.className = "fadeIn";
};
function fadeOut(e) {
e.className = "";
};
fadeOut(slides[curIndex]);
curIndex++;
if (curIndex === slides.length) {
curIndex = 0;
}
fadeIn(slides[curIndex]);
setTimeout(function () {
slideShow();
}, imgDuration);
};
buildSlideShow(imgArray);
slideShow();
CSS:
.mybody{
width: 100%;
min-height: 100vh;
max-height: fit-content;
top: 0px;
left: 0px;
padding: 0px;
/*background: url(../images/slideshow/dog1.jpg);*/
display: flex;
justify-content: center;
align-items: center;
text-align: center;
margin: 0px;
position: relative;
background-repeat: repeat;
}
.mybody img {
transition: opacity 1.5s;
position: absolute;
left: 0;
top: 0;
opacity:0;
background-repeat: repeat;
}
.mybody img.fadeIn {
opacity:1;
}
When I just set the background image as a fixed image (no JS) I get the desired result:
However when I comment out the backgorund image (as in above code) and just have the JS slideshow as the background, this is the result:
I essentially just need this image from the second picture to repeat as in the first picture and cannot figure out how to make this happen although I am sure there is a simple fix/solution. If anyone could be of help it would be much appreciated. Thanks in advance!
You can't repeat an image without duplicating it. But you can repeat background so, you can make the slide using divs with background. Note the usage of css classes instead of jquery fade.
slide = 1;
setInterval(function() {
$(".slide").removeClass("active");
$(".div" + slide).addClass("active");
slide++
if (slide == 4) {
slide = 1;
}
}, 1000)
body {
height: 100vh;
width: 100%;
position: relative;
padding: 0;
margin: 0;
text-align: center;
padding: 30px;
}
.slide {
background-repeat: repeat;
background-size: 100px;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
opacity: 0;
transition: 1000ms all;
}
.slide.active {
opacity: 1;
}
.div1 {
background: url('https://picsum.photos/id/101/200');
}
.div2 {
background: url('https://picsum.photos/id/102/200');
}
.div3 {
background: url('https://picsum.photos/id/103/200');
}
.text {
position: relative;
z-index: 2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<body>
<div class="slide div1">
</div>
<div class="slide div2">
</div>
<div class="slide div3">
</div>
<div class="text">
<h1>dog trainer</h1>
<p>best in the world</p>
</div>
</body>
I am trying to a make carousel using pure Javascript. I successfully manage to slide the carousel and have created left and right buttons.
I took my slide functions and added them to the button on-click event-listener, but I have problems when I implement the function on my buttons. It does not behave as expected. My code is below, how can I fix this?
const images = document.getElementById('imgs'); //here
const allImages = document.querySelectorAll('#imgs img');
const leftBtn = document.getElementById('left');
const rightBtn = document.getElementById('right');
let index = 0;
function changeSliderPage() {
const dot = [...document.getElementsByClassName('star')];
index++;
if (index > allImages.length - 1) {
index = 0
}
imgs.style.transform = `translateX(${-index * 500}px)`;
dot.forEach((dot, i) => {
if (i === index) {
dot.classList.add('active')
} else {
dot.classList.remove('active')
}
});
};
allImages.forEach(i => {
const elem = document.createElement('div');
elem.classList.add('star');
document.body.appendChild(elem)
});
rightBtn.onclick = () => {
changeSliderPage(index + 1);
}
leftBtn.onclick = () => {
changeSliderPage(index - 1);
}
let x = setInterval(changeSliderPage, 100000);
images.onmouseover = () => {
clearInterval(x)
}
images.onmouseout = () => {
x = setInterval(changeSliderPage, 2000);
}
*{
box-sizing: border-box;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.carousel {
overflow: hidden;
width: 500px;
height: 500px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, .3);
border-radius: 5px;
}
.image-container {
display: flex;
transition: transform 300ms linear;
transform: translateX(0);
}
img {
width:500px;
height: 500px;
object-fit: cover;
}
.star{
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 10px;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
background-color: #eeeeee;
}
.star.active{
background-color: red;
}
button{
cursor: pointer;
position: relative;
font-size: 18px;
transition: 0.6s ease;
user-select: none;
height: 50px;
width: 40px;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
top: calc(50% - 25px);
}
button:hover {
background-color: rgba(0,0,0,0.8);
};
button.left {
border-radius: 3px 0 0 3px;
right: 0;
}
button.left {
border-radius: 3px 0 0 3px;
left: 0;
}
<button id="left">❮</button>
<button id="right">❯</button>
<div class="carousel">
<div class="image-container" id="imgs" >
<img src="https://images.unsplash.com/photo-1599736375341-51b0a848f3c7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1573081586928-127ecc7948b0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/flagged/photo-1572850005109-f4ac7529bf9f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
</div>
</div>
Logic that I use with carousels:
for example you have 4 images:
[1][2][3][4]
I have an animation for sliding every image, I add 5th image which is same as image no 1:
[1][2][3][4][1]
Imagine cursor which shows what image is currently displayed, Ill mark cursor as ! !
So at begin:
[!1!][2][3][4][1]
Now the slider moves on...
[1][!2!][3][4][1]
etc...
It moves to last image:
[1][2][3][4][!1!]
And now it has to move under the hood from last image to first image, but without any animation so the whole change is not visible by user:
[!1!][2][3][4][5]
This way you can get inifinite carousel, just need to check in javascript if current image is last one and you want to slide right -> no animation. Same if you are on 1st image and want to slide left.
I have 2 different div, i want the div1 to fade in after 20s and fade-out after 10s and after 30s i want div2 to fade in and after 10s div2 should also fade out. this should keep happening on load of page
bubbleMessage1 = document.getElementById("bubbleMessage1");
bubbleMessage2 = document.getElementById("bubbleMessage2");
bubbleMessage1.style.display = "none";
bubbleMessage2.style.display = "none";
$(function () {
// Different timeouts for each divs
setTimeout(function(){
var times = [20000, 50000];
var counter = 0;
divs = $('#bubbleMessage1, #bubbleMessage2');
function showDiv() {
// hide all divs, filter current index, and fadeIn
divs.hide().eq(counter).fadeIn(500, "linear");
// set time out duration from array of times
setTimeout(showDiv, times[counter]);
// cycle the counter
counter = (counter + 1) % divs.length;
};
showDiv();
}, 20000)
// show first div
});
.chat-bubble-1{
width: 230px;
height: 65px;
background-color: #486622;
text-align: center;
padding: 0.5rem;
line-height: 66px;
color: #fff;
border-radius: 22px;
position: relative;
}
.chat-bubble-1::after{
content: '';
position: absolute;
height: 32px;
width: 32px;
border-bottom: 2px solid #486622;
border-right: 2px solid #486622;
border-left: 0px solid #486622;
border-top: 0px solid #486622;
top : 100%;
left: 74%;
transform: rotate(45deg);
margin-top: -22px;
background: #486622;
}
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in{
animation: fadeIn ease-in 1;
}
.fade-out{
animation: fadeOut ease-in 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chat-container">
<div class="chat-bubble-1" id="bubbleMessage1">
Hi i'm bot How can i help you?
</div>
<div class="chat-bubble-1" id="bubbleMessage2">
I'm still here How can i help you?
</div>
</div>
I tried to use setTimeout loop to achieve this but i was getting error.then i found this jquery method.the problem is the div will not fade-out after 10s. div1 fades and div2 comes immediately. Can anyone please give a solution really appreciate it.thanks
The setTimeout() method of the WindowOrWorkerGlobalScope mixin (and
successor to Window.setTimeout()) sets a timer which executes a
function or specified piece of code once the timer expires.
setTimeout gets extra args you can use in your code.
Change for instance from:
setTimeout(showDiv);
to:
setTimeout(showDiv, times[counter], times, (i+1)%2);
instead of using local vars.
Working demo:
bubbleMessage1 = document.getElementById("bubbleMessage1");
bubbleMessage2 = document.getElementById("bubbleMessage2");
bubbleMessage1.style.display = "none";
bubbleMessage2.style.display = "none";
// Different timeouts for each divs
setTimeout(function(t, i){
var times = t;
var counter = i;
divs = $('#bubbleMessage1, #bubbleMessage2');
function showDiv(t, i) {
var times = t;
var counter = i;
// hide all divs, filter current index, and fadeIn
divs.hide().eq(counter).fadeIn(500, "linear");
// set time out duration from array of times
setTimeout(showDiv, times[counter], times, (i+1)%2);
// ^^^^^^^^^^^^^^^^^^
// params added...
// cycle the counter
counter = (counter + 1) % divs.length;
};
showDiv(times, counter);
}, 2000, [2000, 5000], 0);
// ^^^^^^^^^^^^^^^^^^
// params added...
.chat-bubble-1{
width: 230px;
height: 65px;
background-color: #486622;
text-align: center;
padding: 0.5rem;
line-height: 66px;
color: #fff;
border-radius: 22px;
position: relative;
}
.chat-bubble-1::after{
content: '';
position: absolute;
height: 32px;
width: 32px;
border-bottom: 2px solid #486622;
border-right: 2px solid #486622;
border-left: 0px solid #486622;
border-top: 0px solid #486622;
top : 100%;
left: 74%;
transform: rotate(45deg);
margin-top: -22px;
background: #486622;
}
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in{
animation: fadeIn ease-in 1;
}
.fade-out{
animation: fadeOut ease-in 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chat-container">
<div class="chat-bubble-1" id="bubbleMessage1">
Hi i'm bot How can i help you?
</div>
<div class="chat-bubble-1" id="bubbleMessage2">
I'm still here How can i help you?
</div>
</div>
I'm working with an image fader program, but I'm not understanding absolute positioning. I have the images fading nicely and resizing the way I want if the screen resizes. but I have 2 problems. Div#2 gets covered up by the images. I want div2 to always appear below the image div. Also, I have control buttons on the images. I want them in the middle. I thought using top:50% would do that, but it's not. Here's an example...
var slides = document.querySelectorAll('#slides .slide');
var currentSlide = 0;
var slideInterval = setInterval(nextSlide,5000);
function nextSlide(){goToSlide(currentSlide+1);}
function previousSlide(){goToSlide(currentSlide-1);}
function goToSlide(n){
slides[currentSlide].className = 'slide';
currentSlide = (n+slides.length)%slides.length;
slides[currentSlide].className = 'slide showing';}
var next = document.getElementById('next');
var previous = document.getElementById('previous');
next.onclick = function(){nextSlide();};
previous.onclick = function(){previousSlide();};
#slides {position: relative}
.slide{
position: absolute;
left: 0px;
top: 0px;
width:100%;
height:auto;
min-height:300px;
object-fit:cover;
opacity: 0;
box-sizing:border-box;
transition: opacity 2s;}
.showing{opacity: 1;}
.controls{
background: transparent;
color: #fff;
font-size: 30px;
cursor: pointer;
border: 1px solid #555;
width: 30px;
position: absolute;
}
.controls:hover{ opacity:.5}
.fadenext{right: 10px; top: 50%;}
.fadeprev{left: 10px; top: 50%;}
<br><br>
<div id="slides">
<img src='https://www.panotools.org/dersch/Monp.JPG' class="slide showing">
<img src='https://www.panotools.org/dersch/StBp.JPG' class="slide">
<button class="controls fadeprev" id="previous"><</button>
<button class="controls fadenext" id="next">></button>
</div>
<div style='margin-top:40px;border:1px solid red;width:200px;height:100px'>
This is Div # 2</div>
I've amended your snippet to fix your issues.
Adding margin-top instead of top will fix your issue with the
controls.
Div 2 will now always remain below your slider.
P.S. I moved your div2 inline styles to keep it neat.
var slides = document.querySelectorAll('#slides .slide');
var currentSlide = 0;
var slideInterval = setInterval(nextSlide, 5000);
function nextSlide() {
goToSlide(currentSlide + 1);
}
function previousSlide() {
goToSlide(currentSlide - 1);
}
function goToSlide(n) {
slides[currentSlide].className = 'slide';
currentSlide = (n + slides.length) % slides.length;
slides[currentSlide].className = 'slide showing';
}
var next = document.getElementById('next');
var previous = document.getElementById('previous');
next.onclick = function() {
nextSlide();
};
previous.onclick = function() {
previousSlide();
};
* {
margin: 0;
padding: 0;
}
#slides {
position: relative
}
.slide {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: auto;
min-height: 300px;
object-fit: cover;
opacity: 0;
box-sizing: border-box;
transition: opacity 2s;
}
.showing {
opacity: 1;
}
.controls {
background: transparent;
color: #fff;
font-size: 30px;
cursor: pointer;
border: 1px solid #555;
width: 30px;
position: absolute;
}
.controls:hover {
opacity: .5
}
.fadenext {
right: 10px;
margin-top: 25%;
}
.fadeprev {
left: 10px;
margin-top: 25%;
}
.div2 {
margin-top: 50%;
border: 1px solid red;
width: 200px;
height: 100px;
}
<br><br>
<div id="slides">
<img src='https://www.panotools.org/dersch/Monp.JPG' class="slide showing">
<img src='https://www.panotools.org/dersch/StBp.JPG' class="slide">
<button class="controls fadeprev" id="previous"><</button>
<button class="controls fadenext" id="next">></button>
</div>
<div class="div2">This is Div # 2</div>
It's not feasible to use % based positions when you use "top" style. So to achieve what you want to do, use margin-top instead. As shown below:
.fadenext{right: 10px; margin-top: 25%;}
.fadeprev{left: 10px; margin-top: 25%;}
And for your div2, just change it's style to:
margin-top: 50%
I have made a simple image slider based on this tutorial here. Looks like this:
var currentIndex = 0,
items = $('.container div'),
itemAmt = items.length;
function cycleItems() {
var item = $('.container div').eq(currentIndex);
items.hide();
item.css('display', 'inline-block');
}
var autoSlide = setInterval(function() {
currentIndex += 0;
if (currentIndex > itemAmt - 1) {
currentIndex = 0;
}
cycleItems();
}, 3000);
$('.next').click(function() {
clearInterval(autoSlide);
currentIndex += 1;
if (currentIndex > itemAmt - 1) {
currentIndex = 0;
}
cycleItems();
slide();
});
$('.prev').click(function() {
clearInterval(autoSlide);
currentIndex -= 1;
if (currentIndex < 0) {
currentIndex = itemAmt - 1;
}
cycleItems();
slide();
});
.container {
width: 100%;
height: 100%;
}
.container div {
display: inline-block;
display: none;
}
.container img {
width: 100%;
height: 100%;
object-fit: cover;
}
.galer-btn {
position: absolute;
z-index: 2;
top: 50%;
}
.next {
right: 40px;
padding: 20% 2% 20% 40%;
margin: -20% -1%;
}
.prev {
left: 40px;
padding: 20% 40% 20% 2%;
margin: -20% -2%;
}
.fa {
font-size: 4vw;
color: #ffd2cf;
}
.fa:hover {
cursor: pointer;
-webkit-animation: bounceright .3s alternate ease infinite;
animation: bounceright .3s alternate ease infinite;
}
<html>
<head>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
</head>
<body>
<section class="about">
<i class="fa fa-chevron-right galer-btn next"></i>
<i class="fa fa-chevron-left galer-btn prev"></i>
<div class="container">
<div style="display: inline-block;">
<img src="https://placeimg.com/1000/600/tech" />
</div>
<div>
<img src="https://placeimg.com/1000/600/tech" />
</div>
<div>
<img src="https://placeimg.com/1000/600/tech" />
</div>
<div>
<img src="https://placeimg.com/1000/600/tech" />
</div>
</div>
</section>
</body>
</html>
The result gives me full-screen image slider, which in tutorial is intended to auto slide, but I have managed to disable that by changing currentIndex += 1; to currentIndex += 0; in javascript code. Btw, any recommendations on how to remove the auto slide properly are welcomed.
However, the main question is how do I add some transition effects between images like fade-out etc.?
Also, for left and right buttons I have simply used FontAwesome icons, and it kinda works, but something tells me that might not be the best approach.. Should I use <button> or smthn instead?
So far I have only been learning HTML and CSS, and javascript (or jQuery) is a complete mystery to me right now, so I appreciate any help.