Change of opacity using css transition and vanilla JavaScript works only when fading out - javascript

This codepen shows my problem: http://codepen.io/PiotrBerebecki/pen/pNvpdG
When the user clicks on the big button the css opacity is reduced to 0. Since I've applied the following rule: transition: opacity 0.5s ease-in-out; the fade out animation is smooth.
I would like to achieve the same smooth transition when the next button fades in.
However for some reason the next button appears suddenly without any transition.
Would you know what causes the issue and how to fix it?
console.clear();
(function() {
// Data for the app
const model = {
buttons: ['tomato', 'blue'],
currentButton: -1
};
// Logic for the app
const controller = {
init: function() {
view.init();
},
getButtonName: function() {
model.currentButton = (model.currentButton + 1) % model.buttons.length;
return model.buttons[model.currentButton];
}
};
// View for the app
const view = {
init: function() {
this.root = document.getElementById('root');
this.showNext();
},
animationDelay: 500,
showNext: function() {
// Get next button name
const buttonName = controller.getButtonName();
// Create button DOM element
const buttonElement = document.createElement('div');
buttonElement.className = 'button';
buttonElement.id = buttonName;
buttonElement.textContent = buttonName;
buttonElement.style.opacity = 0;
// Add event listender for the button
buttonElement.addEventListener('click', event => {
// Reduce opacity
buttonElement.style.opacity = 0;
// Remove the button from DOM
setTimeout(() => {
this.root.removeChild(buttonElement);
}, this.animationDelay + 10);
// Start the function to show next button
setTimeout(() => {
this.showNext();
}, this.animationDelay + 20);
});
// Add button to DOM
this.root.appendChild(buttonElement);
// Show button by increasing opacity
buttonElement.style.opacity = 1;
}
};
// Start the app
controller.init();
}());
#tomato {
background: tomato;
}
#blue {
background: DeepSkyBlue;
}
.button {
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
<div id="root"></div>

This should work , Code pen link: http://codepen.io/saa93/pen/gLbvmQ
You would need to add this instead of directly setting opacity to 1
// Show button by increasing opacity
buttonElement.style.opacity = 0;
setTimeout(() => {
buttonElement.style.opacity = 1;
}, this.animationDelay + 20);

Add a class (in the Snippet is .active) add the following:
CSS
.button {
opacity: 0;
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
.button.active {
opacity: 1;
transition: opacity 0.5s ease-in-out;
}
JavaScript
...
// Reduce opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 0;
...
// Show button by increasing opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 1;
SNIPPET
console.clear();
(function() {
// Data for the app
const model = {
buttons: ['tomato', 'blue'],
currentButton: -1
};
// Logig for the app
const controller = {
init: function() {
view.init();
},
getButtonName: function() {
model.currentButton = (model.currentButton + 1) % model.buttons.length;
return model.buttons[model.currentButton];
}
};
// View for the app
const view = {
init: function() {
this.root = document.getElementById('root');
this.showNext();
},
animationDelay: 500,
showNext: function() {
// Get next button name
const buttonName = controller.getButtonName();
// Create button DOM element
const buttonElement = document.createElement('div');
buttonElement.className = 'button';
buttonElement.id = buttonName;
buttonElement.textContent = buttonName;
buttonElement.style.opacity = 0;
// Add event listender for the button
buttonElement.addEventListener('click', event => {
// Reduce opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 0;
// Remove the button from DOM
setTimeout(() => {
this.root.removeChild(buttonElement);
}, this.animationDelay + 10);
// Start the function to show next button
setTimeout(() => {
this.showNext();
}, this.animationDelay + 20);
});
// Add button to DOM
this.root.appendChild(buttonElement);
// Show button by increasing opacity
buttonElement.classList.toggle('active');
buttonElement.style.opacity = 1;
}
};
// Start the app
controller.init();
}());
#tomato {
background: tomato;
}
#blue {
background: DeepSkyBlue;
}
.button {
opacity: 0;
transition: opacity 0.5s ease-in-out;
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
}
.button.active {
opacity: 1;
transition: opacity 0.5s ease-in-out;
}
<div id="root"></div>

after this.root.appendChild(buttonElement);
you should set opacity to 0 and let the browser time to render before buttonElement.style.opacity = 1;
BTW I think removing and adding the element of not a good way to do this
.button {
width: 100%;
height: 50vh;
border: solid 3px black;
cursor: pointer;
animation-name: example;
animation-duration:3.5s;
}
#keyframes example {
0% {opacity:1}
50% {opacity:0}
100% {opacity:1}
}
What U really want is to use animation like this:JSFIDDLE EXAMPLE
This way the animation does all this timing and opacity back and forth using the css only

Related

Create blinking countdown timer in CSS

I am trying to create a blinking countdown timer, starting it at 5 seconds, and disappearing when it gets to 0.
CSS:
.blinky {
transition: 1s opacity;
-moz-transition: 1s opacity;
-webkit-transition: 1s opacity;
}
HTML:
<div id="countdown" class="blinky">
JS:
const cdStart = 5;
countdown.innerHTML = cdStart;
countdown.style.opacity = 0;
for (var i = cdStart - 1; i > 0; i--) {
setTimeout(
(x) => {
countdownTime.innerHTML = x;
countdown.classList.remove('blinky');
countdown.style.opacity = 1;
countdown.classList.add('blinky');
countdown.style.opacity = 0;
},
1000 * (cdStart - i),
i
);
}
What I want this to do is to show 5, fade out, 4, fade out, 3, fade out, 2, fade out, 1, fade out. When a new number is shown on the timer, I want it to show up instantly, and not fade back in. For that reason, I remove the "blinky" class before I set the opacity to 1, then add it back in before setting opacity to 0.
Unfortunately, this doesn't seem to work - 5 shows up and fades out, and then nothing else shows up. If I remove the manipulation of countdown's style (and just set the innerHTML in the for loop), I see that the timer displays properly (counts down from 3 to 1), so that's working.
I thought, maybe the browser is having trouble removing a class and then immediately adding it back in, so I separated those events by a bit:
CSS:
.blinky {
transition: .9s opacity;
-moz-transition: .9s opacity;
-webkit-transition: .9s opacity;
}
JS:
const cdStart = 5;
countdownTime.innerHTML = cdStart;
countdown.style.opacity = 0;
for (var i = cdStart - 1; i > 0; i--) {
setTimeout(
(x) => {
countdownTime.innerHTML = x;
countdown.classList.remove('blinky');
countdown.style.opacity = '';
},
1000 * (cdStart - i),
i
);
setTimeout(() => {
countdown.classList.add('blinky');
countdown.style.opacity = 0;
}, 1000 * (cdStart - i) + 100);
}
This one was closer - I saw 5, fade out, then nothing for a bit, and 1 came in and then faded out.
Is there a more reliable way to get the desired behavior here?
With CSS Animations you can create the fade-out for every second that is changed in the counter.
Add an animation with 5 iterations and listen for the animationiteration and animationend events. These events are fired for every time the animation plays and restarts, and for when the animation is finished.
Change the count and update the textContent of the countdown in both event handlers.
const countdown = document.querySelector('#countdown');
let count = 5;
function updateCount() {
count--;
countdown.textContent = count;
}
countdown.textContent = count;
countdown.classList.add('blinky');
countdown.addEventListener('animationiteration', updateCount);
countdown.addEventListener('animationend', updateCount);
#keyframes blink-out {
0%, 25% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.blinky {
font-size: 48px;
animation: blink-out 1s ease-out forwards 5;
}
<div id="countdown"></div>
Hope I understood correctly :
let clock = document.getElementById('seconds');
let secondsRemaining = 5;
clock.innerText = secondsRemaining;
clock.classList.add('animation');
const myInterval = setInterval(()=>{
secondsRemaining--;
clock.innerText = secondsRemaining;
if(!secondsRemaining)
stopAnimation();
},1000)
function stopAnimation(){
clock.classList.remove('animation');
clearInterval(myInterval);
}
.clock{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
.animation{
animation:1s fade-out ease;
animation-iteration-count:infinite;
animation-fill-mode:forwards;
}
#seconds{
font-size:10rem;
}
#keyframes fade-out{
from{opacity:1}
99%{opacity:0}
to{opacity:1}
}
<body>
<div class="clock">
<span id="seconds"></span>
</div>
</body>
Here is an example using async functions and css transition to control fading.
const wait = ms => new Promise(r => setTimeout(r, ms));
const $ = str => document.querySelector(str);
const btn = $("button");
const number = $(".number");
const DELAY_TIME = 1000;
async function changeNumber(newVal) {
number.classList.add("fade");
await wait(DELAY_TIME);
number.textContent = newVal;
number.classList.remove("fade");
await wait(DELAY_TIME);
}
async function countFrom(n) {
const STARTING_VALUE = n;
number.textContent = STARTING_VALUE;
await wait(DELAY_TIME);
for (let counterVal = STARTING_VALUE - 1; counterVal >= 0; counterVal--) {
await changeNumber(counterVal);
}
}
btn.addEventListener("click", async () => {
btn.disabled = true;
await countFrom(5);
btn.disabled = false;
});
.timer {
display: grid;
place-items: center;
width: 100px;
height: 150px;
border-radius: 20px;
border: 5px solid lightgreen;
}
.number {
font-size: 5rem;
font-family: monospace;
transition: opacity 1s;
}
.number.fade {
opacity: 0;
}
<div class="timer">
<span class="number"></span>
</div>
<br />
<button>count from 5!</button>

The equivalent of pointer-events:none in javascript

I'm facing a problem with wiggling bottom border pseudo css element, pointer events set to none fixes it but I have decide to go with javascript and create a span on mouse enter event and remove it on mouse leave event. with set time method, I created an acceptable animation like feeling but now back to the same problem WIGGLING. So is there an equivalent code in javascript that mimics pointer events set to none?
<a class="top-link">
<span class="title"> Title </span>
</a>
.border-bottom {
border-bottom: solid 3px #ddd;
content: "";
width: 100%;
position: absolute;
top: 100%;
z-index: 1;
left: 0;
transform: translateY(4px);
transition: ease-in 0.2s;
opacity: 0;
}
document.querySelectorAll(".top-link").forEach((el) => {
el.addEventListener("mouseenter", function () {
el.insertAdjacentHTML("beforeend", '<span class="border-bottom"></span>');
el.childNodes.forEach((e) => {
if (e.className == "border-bottom") {
setTimeout(() => {
e.style.transform = "translateY(0px)";
e.style.opacity = "1";
}, 50);
}
});
});
el.addEventListener("mouseleave", function () {
el.childNodes.forEach((e) => {
if (e.className == "border-bottom") {
setTimeout(() => {
e.style.transform = "translateY(4px)";
}, 25);
setTimeout(() => {
e.style.opacity = "0.4";
}, 50);
setTimeout(() => {
e.style.opacity = "0";
e.remove();
}, 250);
}
});
});
});

How to add animation?

How will I add fadeout animation in this javascript code?
document.getElementById("mt-alerts").style.display="block";
setTimeout(function(){
document.getElementById("mt-alerts").style.display="none";
}, 2000);
Instead of using display, you need to start with opacity for this.
The idea is simply decrease the opacity of your element until it reaches the 0, then set its display as none. To fade in you can repeat the idea in reverse.
function js_fadeOut(targetID, intervalMs, fadeWeight) {
var fadeTarget = document.getElementById(targetID);
var fadeEffect = setInterval(function () {
if (!fadeTarget.style.opacity) {
fadeTarget.style.opacity = 1;
}
if (fadeTarget.style.opacity > 0) {
fadeTarget.style.opacity -= fadeWeight;
} else {
fadeTarget.style.display = "none";
clearInterval(fadeEffect);
}
}, intervalMs*fadeWeight);
}
<div id='target' style='padding:8px; background:lightblue;' onclick='js_fadeOut("target", 200, 0.1)'>Click to fadeOut</div>
You should make classses for every animations, and the JS should change only the classes of the items.
You can with this method, make your own animatsions.
const alertMsg = document.getElementById("mt-alerts");
const hide = document.getElementById("hide");
const red = document.getElementById("red");
hide.addEventListener("click", ()=> alertMsg.classList.toggle("hidden"));
red.addEventListener("click", ()=> alertMsg.classList.toggle("red"));
#mt-alerts {
opacity: 1;
transition: all 0.5s linear;
color: black;
}
.hidden {
opacity: 0!important;
}
.red {
color: red!important;
}
<div id="mt-alerts">My Alert</div>
<button id="hide">Hide/show</button>
<button id="red">Make it red</button>

Softly Transition HTML Images with Javascript

I am trying to use JS to switch images, the code does what it is supposed to and switches the images, however, I want a fade out-fade in effect to the image transition. I tried to declare a CSS Transition for opacity and change the opacity first, which didn't work, then I tried to change the opacity with plain JS, however that didn't work either, what would be the best way to achieve this?
My Poorly Designed Image Change Code:
image = [
"image_1.png",
"image_2.png",
"image_3.jpeg"
];
updateImg = async() => {
console.log("Pulling Image Change")
var img = document.getElementById("img-pan");
console.log(`Got ${img} with current src ${img.src}`)
var exi_bool = false;
for(i = 0; i < image.length - 1; i++) {
if(img.src.endsWith(image[i])) { exi_bool = true; console.log(`Found current src to == image[${i}]`) ;break; }
}
if(!exi_bool) {
img.src = image[0];
}else {
if(i < image.length - 1) { i++ }else { i = 0 }
img.src = image[i];
}
}
If I understood well, before you replace the image add a class that define the opacity to 0.3 for example.
document.getElementById("MyElement").classList.add('MyClass');
when the image change you remove the class.
document.getElementById("MyElement").classList.remove('MyClass');
Note that your image has to be set on css as opacity: 1 and transition x seconds.
Will use css style animation, just change class name, is simple to use and build.
but when css animation start to change css property,no way could change same property but other css animation.
let imgArray = [
'https://fakeimg.pl/100x100/f00',
'https://fakeimg.pl/100x100/0f0',
'https://fakeimg.pl/100x100/00f'
];
let img = document.getElementsByTagName('img')[0];
//only two function
async function fadeOut(element) {
element.className = 'fade-out';
}
async function fadeIn(element) {
element.className = 'fade-in';
}
//
let i = 0;
function loop() {
img.src = imgArray[i % 3];
i++;
fadeIn(img).then(res => {
setTimeout(() => {
fadeOut(img).then(res => {
setTimeout(() => {
loop();
}, 1000);
})
}, 1000);
})
}
loop();
img {
position: relative;
left: 0; /* or use transform */
opacity: 1;
transition: 1s;
width: 100px;
display: block;
margin: auto;
}
.fade-in {
animation: fade-in 1s;
}
#keyframes fade-in {
0% {
left: 100px; /* or use transform */
opacity: 0;
}
100% {
left: 0; /* or use transform */
opacity: 1;
}
}
.fade-out {
animation: fade-out 1s both;
}
#keyframes fade-out {
0% {
left: 0; /* or use transform */
opacity: 1;
}
100% {
left: -100px; /* or use transform */
opacity: 0;
}
}
<img src="https://fakeimg.pl/100x100/#f00">

How to change opacity with javascript

I am trying to fade an element that is being created dynamically with JavaScript.
Here's a CSS example of what I am trying to do: https://codepen.io/deejay/pen/OJJqZaL
Javascript
...
const fadeOutWithOpacity = () => {
const opacity = totalCount >= 1 && 0.5;
return opacity;
};
const handleOpacity = () => {
setInterval(() => {
fadeOutWithOpacity();
}, 3000);
};
...
style: {
background: "#FA4379",
color: "#fff",
opacity: `${handleOpacity()}`
}
I only want to change the opacity value every 3sec
You can use Javascript to add a class to your element which will cause the opacity to decrease slowly thanks to the CSS transition property.
const spawnBox = () => {
var box = document.createElement("div");
box.className = "box";
box.onclick = (event) => {
box.classList.add("hidden");
};
document.body.appendChild(box);
};
spawnBox();
setInterval(() => {
spawnBox();
}, 1000);
.box {
width: 20px;
height: 20px;
margin: 5px;
background: red;
transition: opacity .5s;
}
.box.hidden {
opacity: 0;
}

Categories