I am trying to apply 'opacity / sliding to left' for my automatic slider but I couldn't make it. Please help me with this.
let images = ["images/a.jpg", "images/b.jpg", "images/c.jpg", "images/d.jpg", ];
let i = 0;
function changeImg() {
document.querySelector("#slider img").src = images[i];
if (i < images.length - 1) {
i++;
} else {
i = 0;
}
setTimeout("changeImg()", 1000);
}
onload(changeImg());
#slider img {
width: 100vw;
height: 60vh;
transition: opacity 2s ease-out;
}
<section id="slider">
<img name="slide" width="400" height="200" />
</section>
The initial requirement is for the image to fade and another one be shown.
This can be achieved by placing the images one on top of the other (position absolute) and opacity 0 with a transition set on opacity. When it is a particular images turn to be shown the image before it is set to opacity 0 and the new image has its opacity set to 1.
let images = ["https://picsum.photos/id/1015/300/300", "https://picsum.photos/id/1016/200/300", "https://picsum.photos/id/1018/300/200.jpg", "https://picsum.photos/id/1022/400/300", ];
const slider = document.querySelector('#slider');
const imgEls = [];
images.forEach(image => {
let imgEl = document.createElement('img');
imgEl.src = image;
imgEls.push(imgEl);
slider.appendChild(imgEl);
});
let i = 0;
function changeImg() {
imgEls[i].style.opacity = 0;
if (i < images.length - 1) {
i++;
} else {
i = 0;
}
imgEls[i].style.opacity = 1;
setTimeout("changeImg()", 1000);
}
window.onload = changeImg;
#slider {
width: 100vw;
height: 60vh;
position: relative;
isplay: felx;
justify-content: center;
align-items: center;
}
#slider img {
display: inline-block;
width: 100vw;
height: 60vh;
object-fit: contain;
transition: opacity 2s ease-out;
opacity: 0;
position: absolute;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="slider">
<https://stackoverflow.com/questions/69870264/how-to-add-css-transitions-to-automatic-slider#img name="slide" width="400" height="200" />
</section>
While the action seems to correspond to what was discussed in the comments it doesn't make a real 'slider' and the question also talks of sliding to the left using CSS.
This snippet takes a slightly different approach to the question's code in that once the initial set up of the slides has been done using Javascript everything else is done via CSS. This has the advantage that it's possible the system can just hand the animation to the GPU without needing to interrupt back to the main program on a timeout.
Each image is located at left 100% (ie just off screen to the right) and it is given the same animation as the other - move to the center, wait and then move out to the left - opacity fading in and out respectively. The images however start animating at staggered times so the sliding looks continuous.
const slider = document.querySelector('#slider');
const images = ["https://picsum.photos/id/1015/300/300", "https://picsum.photos/id/1016/200/300", "https://picsum.photos/id/1018/300/200", "https://picsum.photos/id/1022/400/300"];
let div;
let count = 0;
images.forEach(image => {
div = document.createElement('div');
div.style.animationDelay = (count * 2) + 's';
count++;
div.style.setProperty('--img', 'url(' + image + ')');
slider.appendChild(div);
});
slider.style.setProperty('--n', count);
#slider {
overflow: hidden;
width: 100vw;
height: 60vh;
position: relative;
}
#slider div {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0;
display: inline-block;
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
background-image: var(--img);
animation-name: slide;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: calc(var(--n) * 2s);
animation-fill-mode: forwards;
}
#keyframes slide {
0% {
opacity: 0;
transform: translateX(100vw);
}
12.5% {
opacity: 1;
transform: translateX(0);
}
25% {
opacity: 1;
transform: translateX(0);
}
37.5%,
100% {
opacity: 0;
transform: translateX(-100vw);
}
}
<div id="slider"></div>
Note that the keyframes settings assume 4 images. The % values would have to be changed for more or fewer. Unfortunately CSS does not allow variables as % values in keyframes so the JS would ideally find the number of images and create the correct keyframes.
Related
I want to make few images displaying as slides with fadeIn effect in css. Everything works fine, images are displayed in 3s period with setInterval javascript method, but only first image displays with fadeIn animation.
.slide {
position: absolute;
height: 100vh;
width: 66vw;
animation: fadeIn 1s;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<img class="slide" src="https://static.vecteezy.com/packs/media/components/global/search-explore-nav/img/vectors/term-bg-1-666de2d941529c25aa511dc18d727160.jpg">
There is only one jpg added to HTML and javascript code is written to replace file path from
<img class="slide" src="1.JPG">
to "2.jpg", "3.jpg" etc
Only first image has animation, everything displayed later is without animation.
When I check console, all next images still have .slide class and all its properties position/width/height/animation, but they display without animation.
Any ideas ?
Basically, you need to trigger the css animation every time you change the src. You can do it by removing the element class, triggering a DOM reflow, and adding the class again. But you should be careful because triggering reflow can be an expensive operation. Read more about it here.
const images = [
"https://via.placeholder.com/300?text=image1",
"https://via.placeholder.com/300?text=image2",
"https://via.placeholder.com/300?text=image3",
];
const img = document.querySelector(".slide");
let imageIndex = 0;
const imageInterval = setInterval(() => {
imageIndex++;
if (imageIndex >= images.length) {
clearInterval(imageInterval);
} else {
img.src = images[imageIndex];
img.classList.remove("slide");
void img.offsetWidth; // trigger a DOM reflow
img.classList.add("slide");
}
}, 3000);
.slide {
position: absolute;
height: 100vh;
width: 66vw;
animation: fadeIn 1s;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<img class="slide" src="https://via.placeholder.com/300?text=image1">
Hard to tell what exactly you want but with pure CSS perhaps something like this
.slide {
position: absolute;
opacity: 0;
height: 100vh;
width: 66vw;
animation: fadeIn 1s forwards;
}
.two {
animation-delay: 3s;
}
.three {
animation-delay: 6s;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<img class="slide" src="https://static.vecteezy.com/packs/media/components/global/search-explore-nav/img/vectors/term-bg-1-666de2d941529c25aa511dc18d727160.jpg">
<img class="slide two" src="https://compote.slate.com/images/f063a07e-e5ab-4e04-8093-281d0a28ebe8.jpeg">
<img class="slide three" src="https://i.ytimg.com/vi/nWLUdoK5fSs/maxresdefault.jpg">
I'm trying to build out a super simple Super Mario-style game using just HTML, CSS and JS.
I'm not using <canvas> just building the whole thing out in simple divs, and getting the movement of the background and characters with CSS Animations.
The part where I'm running into issues is getting collision detection between the character and the monsters. Basically what I want to happen is if the character at all touches the monster, the game is over, and you avoid the monsters by jumping.
I have tried different snippets of JS for div collision detection, but the issue there is the code returns the static X and Y positions of the div, and not that of each keyframe in the CSS animation.
Doing some digging, I found a way for the code to track the X and Y of each keyframe by adding an event listener to my monster and character divs:
shadow1.addEventListener('animationiteration', function (event) {
shadowDiv = this.getBoundingClientRect();
console.log(shadowDiv);
});
cont.addEventListener('animationiteration', function (event) {
charDiv = this.getBoundingClientRect();
console.log(charDiv);
});
The above returns all the X and Y positions as the animation is running into the console for both the monster and the character, but the issue I'm running into with this, is that it only returns the keyframes if it's inside the scope of the event listener. I have tried every which way to get the same thing to happen in a global scope, but everytime I do, it returns a value of undefined, and from there I am basically stuck. and not sure how to move forward.
Any help would be appreciated!
Below is the relevant code:
HTML
<div id="char-container"></div>
<div id="shadow-container-1"> </div>
<div id="btn"> Jump! </div>
CSS
#keyframes rtol {
0% { left: 800px; opacity: 1;}
80% { opacity: 1;}
85%{ opacity: 0.75;}
90% { left: -220px; opacity: 0;}
100% { left: -220px; opacity: 0;}
}
#shadow-container-1{
width: 100px;
height: 160px;
position: absolute;
display: block;
bottom: 450px;
left: 800px;
opacity: 1;
animation-name: rtol;
animation-iteration-count: infinite;
animation-direction: normal;
animation-timing-function: linear;
animation-fill-mode: backwards;
#keyframes jump {
from { bottom: -50px; left: 0px; }
to { bottom: 400px; left: 150px; }
}
#char-container{
width: 150px;
height: 200px;
position: relative;
bottom: -50px;
}
JS
let btn = document.getElementById('btn');
let cont = document.getElementById('char-container');
btn.addEventListener('click', function(e){
if(e.target = btn){
cont.style.webkitAnimationPlayState = 'running';
cont.style.webkitAnimation = 'jump 1.25s ease 2';
cont.style.webkitAnimationDirection = 'alternate';
}
});
cont.addEventListener("webkitAnimationEnd", function(e){
cont.style.webkitAnimation = '';
});
let shadow1 = document.getElementById('shadow-container-1');
shadow1.style.webkitAnimationDuration = Math.floor(Math.random() * 15) + 3 + 's';
shadow1.addEventListener('animationiteration', function (event) {
shadowDiv = this.getBoundingClientRect();
console.log(shadowDiv);
});
cont.addEventListener('animationiteration', function (event) {
charDiv = this.getBoundingClientRect();
console.log(charDiv);
});
hi im wondering why my css transition is not working. the carousel does the loop and and all, but my transition only works when i open dev tools and point at the element with my mouse.
heres the code : https://codepen.io/anon/pen/zXQpNo
thanks for your help
var slides = Array.from(document.querySelectorAll(".slide_element"));
var i = 0;
function test(){
if(i === slides.length - 1){
slides[slides.length - 1].classList.remove("displaying");
i = 0;
slides[i].classList.add("displaying");
}
else{
slides[i].classList.remove("displaying");
slides[i+1].classList.add("displaying");
i++;
}
}
setInterval(() => {
test();
}, 3000);
in "slide_element" remove display: none; and the transition add to it (all) so it will become like this transition: all .3s;
and set it to absolute positioning, so your css would look like this:
.slide_element{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: all 0.3s;
transform: translateX(1000px);
}
I am trying to build a simple web element that resembles the wheel contestants spin on The Price is Right (sample video). My question is: is there a more efficient way to achieve this effect than what I've cobbled together below?
My first attempt at this functionality basically decrements the translateY property of an element that contains the elements to be spun [codepen]:
setInterval(shiftCards, 100)
var translateY = -60,
cardIdx = 0,
startCards = 60,
wrap = document.querySelector('.wrap');
for (var i=0; i<startCards; i++) {
addCard()
}
function addCard() {
var div = document.createElement('div');
div.className = 'card';
div.style.top = (cardIdx * 12) + 'px';
wrap.appendChild(div);
cardIdx++;
}
function shiftCards() {
wrap.style.transform = 'translateY(' + translateY + 'px)';
translateY -= 12;
var cards = wrap.querySelectorAll('.card');
if (cards.length >= startCards) {
cards[0].parentNode.removeChild(cards[0]);
addCard();
}
}
.cards {
width: 80px;
height: 200px;
overflow: hidden;
background: #aaa;
}
.wrap {
position: relative;
transition: transform .25s;
}
.card {
width: 100%;
height: 10px;
margin: 2px 0;
background: red;
position: absolute;
left: 0;
right: 0;
}
<div class='cards'>
<div class='wrap'>
</div>
</div>
Is there a more efficient way to achieve this functionality? Can I create an element with n children and actually just spin them in the Z-dimension, rather than create an artificial spin as I've done above? Any guidance others can offer on this question will be very appreciated!
You can use css-animations for this: (They are probably more efficient)
/* only alignment */
body, html {
height: 100%;
margin: 0;
padding: 0;
}
.wrapper {
display:flex;
justify-content:center;
align-items:center;
height: 100%;
}
/* actual spinning */
img {
animation: spin 5s infinite linear;
/*
spin: the keyframes (=animation) we want to have
5s: how long it should take for one iteration
infinite: how often should it repeat
linear: the easing between the different key frames You can also try 'ease'
*/
}
#keyframes spin {
0% {transform: translateY(-60px);} /* Starting point */
100% {transform: translateY(-360px);} /* end point */
}
#-webkit-keyframes spin {
0% {transform: translateY(-60px);}
100% {transform: translateY(-360px);}
}
<div class="wrapper">
<img src="https://www.placecage.com/300/100" class="spin">
</div>
I know how to run the animation from point A to point B, so to speak, but do not know how to run continuously in a circle. Below is a small code prepared:
.bg {
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg) top left/30%;
animation: bg 2s cubic-bezier(0, -0.02, 1, 0.99);
}
#keyframes bg {
0% {
background-position: left -100px;
}
100% {
background-position: left 0px;
}
}
<div class="bg"></div>
help with script
If by:
run continuously in a circle
You mean run animation in a loop, then you can add the infinite animation-iteration-count property. In the shortcode you can just add infinite to your animation property. See demo:
.bg {
display: block;
position: absolute;
width: 100%;
height: 100%;
background: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg) top left/30%;
animation: bg 2s cubic-bezier(0, -0.02, 1, 0.99) infinite;
}
#keyframes bg {
0% {
background-position: left -100px;
}
100% {
background-position: left 0px;
}
}
<div class="bg"></div>
Edit: jQuery Solution
With jQuery you can use the animate() function to achieve the same effect.
// bg animation function
function bgAnimate(speed) {
// define bg div
var el = $('.bg');
// get current background y-axis position and convert to integer (strips `px`)
var posY = parseInt(el.css("background-position-y"));
// animate element
el.animate({
'background-position-y': posY + 100 // add 100px
},{
duration: speed,
easing: 'linear',
complete: function() {
bgAnimate(speed); // repeat aniamtion (loop)
}
});
}
bgAnimate(1000); // call function
html, body {padding: 0;margin: 0;}
.bg {
display: block;
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-image: url(http://www.dejurka.ru/wp-content/uploads/2015/06/watercolor-patterns4.jpg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="bg"></div>