Multiple actions for one button - javascript

I'm trying to make full screen menu like a modal.
Everything is fine except fadeOut animation.
Can someone explain what is wrong with my scripts/codes?
I want to make this content fades in when click the button but fades out when its clicked again. My script sets the value of "display" but in animation only fade in effect works fine. In reverse fade out do effect instantly (without 0.5s animation duration). Button has got z-index = 101 and menu-content = 100 so the button stay at the same place all the time.
Thanks
function myMenu() {
var x = document.getElementById("menu-content");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
if (x.style.animation === "fadeIn 0.5s ease-in-out") {
x.style.animation = "fadeOut 0.5s ease-in-out";
} else {
x.style.animation = "fadeIn 0.5s ease-in-out";
}
}
#menu-content {
display: none;
position: absolute;
height: 100%;
width: 100%;
background: linear-gradient(-25deg, #c0a0ae, #6f448a);
z-index: 100;
top: 0;
left: 0;
animation: fadeOut 0.5s ease-in-out;
}
.menu-content-properties {
height: 100%;
width: 100%;
display: grid;
grid-template-columns: auto;
background: #000000;
opacity: 0.5;
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
<button id="menu-button" style="z-index: 101; position: absolute; top: 0;
left: 0;" onclick="myMenu();">Menu</button>
<div id="menu-content"></div>
<div id="menu-content">
<div class="menu-content-properties">
<div>1</div>
<div></div>
<div>2</div>
</div>
</div>

Okay, so there are a couple of issues.
Firstly, in your HTML, there are 2 elements with the same ID (menu-content) which will cause a couple of problems, so remove one of those.
Secondly, when you set display: none in your myMenu function, it will immediately be hidden, so that's why the animation is not shown.
You have a couple of options:
Put that code within a setTimeout so that it isnt set to display: none until the animation has finished, OR
Don't use display: none
Personally, I think you're better off not using display: none, otherwise you need to amend your javascript whenever you change the duration of the animation.
I've managed to get it working without the need for display none, and using CSS transitions which works quite nicely
function myMenu() {
var x = document.getElementById("menu-content");
if (x.classList.contains("open")) {
x.classList.remove("open");
} else {
x.classList.add("open");
}
}
#menu-content {
position: absolute;
height: 100%;
width: 100%;
background: linear-gradient(-25deg, #c0a0ae, #6f448a);
z-index: 100;
top: 0;
left: 0;
transition: opacity 0.5s ease-in-out;
opacity: 0;
}
#menu-content.open {
opacity: 1;
}
.menu-content-properties {
height: 100%;
width: 100%;
display: grid;
grid-template-columns: auto;
background: #000000;
opacity: 0.5;
}
<button id="menu-button" style="z-index: 101; position: absolute; top: 0;
left: 0;" onclick="myMenu();">Menu</button>
<div id="menu-content">
<div class="menu-content-properties">
<div>1</div>
<div></div>
<div>2</div>
</div>
</div>

Related

css transitions don't work when changes are made in javascript

#loading_screen {
display: none;
z-index: 1;
height: 100vh;
width: 100vw;
opacity: 0;
background-color: red;
transition: opacity 4s 0s ease;
}
<div id="loading_screen" class="page">
</div>
<script>
function hide_page() {
const loading = document.getElementById('loading_screen');
loading.style.display = 'block';
loading.style.opacity = '1';
}
hide_page()
</script>
The loading_screen div appears instantly, as if the transition didn't even exist
Is there a chance that the css is not functional immediately when I run the page?
You need to wait for the browser to update and paint the loading element first, then you can use setTimeout to change the opacity after the browser has done its paint.
function hide_page() {
const loading = document.getElementById('loading_screen');
loading.style.display = 'block';
setTimeout(() => {
loading.style.opacity = '1';
});
}
hide_page();
#loading_screen {
display: none;
z-index: 1;
height: 100vh;
width: 100vw;
opacity: 0;
background-color: red;
transition: opacity 4s ease;
}
<div id="loading_screen" class="page">
</div>

How to make an image fade in and another fade out with one button click?

I'm trying to fade in the blue square with the first click of the button. And then on the second click, the blue square fades out and the red one fades in.
As you can see when you test it, it doesn't work that way. I don't know where I am wrong and If anyone can show me how to fix it I'd appreciate it.
var currentscene = 0;
function next() {
currentscene++;
if (currentscene = 1) {
var element = document.getElementById("blue");
element.classList.add("fade-in");
}
if (currentscene = 2) {
var element = document.getElementById("blue");
element.classList.add("fade-out");
var element = document.getElementById("red");
element.classList.add("fade-in");
}
}
.squareblue {
height: 50px;
width: 50px;
top: 50px;
background-color: blue;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.squarered {
height: 50px;
width: 50px;
top: 100px;
background-color: red;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.fade-out {
animation: fadeOut ease 2s
}
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fade-in {
animation: fadeIn ease 2s
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>
A few mistakes, and a few things to improve.
Inside your if conditionals, you were assigning the value of 1 and 2 to the variable currentscene instead of using the comparison operator ==. I added the remainder operator to be able to continue the loop indefinitely.
Instead of grabbing the element from the dom each loop, I just defined the elements at the top, and continued to reference the save variable.
instead of using a css keyframes animation, I used the css transition property to add animation to the changing of opacity.
If you have any questions, please ask 🚀
let currentscene = 0;
const blue = document.getElementById("blue");;
const red = document.getElementById("red");;
function next() {
currentscene++;
if (currentscene % 2 == 0) {
blue.classList.remove("opaque");
red.classList.add("opaque");
}
else if (currentscene % 2 == 1) {
red.classList.remove("opaque");
blue.classList.add("opaque");
}
}
.squareblue,
.squarered {
height: 50px;
width: 50px;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
transition: 1s;
}
.squareblue {
top: 50px;
background-color: blue;
}
.squarered {
top: 100px;
background-color: red;
}
.opaque {
opacity: 1;
}
button {user-select: none}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>

Clicking a button to initiate an animation, then clicking another button to revers that animation

I created a button where you can click it. It then initiates a CSS animation where some buttons and text flow down the screen saying are you sure you want to do this? They can then click the yes or no button and I want it to reverse the animation back up. I have completed the animation going down but I can't manage to repeat that animation going back up when they click a button.
Here is the HTML:
<button onclick="confirm()">Delete</button>
<div id="wholeshow" class="confirm-whole">
<h1 class="confirm">Delete</h1>
<p class="confirm">Are you sure you want to delete ____?</p>
<button class="confirm" onclick="reset()">Delete</button>
<button class="confirm" onclick="cancel()">Cancel</button>
</div>
Here is the JS:
function confirm() {
document.getElementById("wholeshow").classList.add("add");
}
and here is the CSS:
.confirm-whole {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: grey;
animation: slideIn 0.5s forwards;
}
#keyframes slideIn {
0% {
top: -250px;
height: 0%;
}
99% {
height: 0%;
}
100% {
top: 0px;
height: 100%;
}
}
.add {
display: block;
}
Thanks so much for the help!
The JavaScript isn't pretty but it works, perhaps a better solution would be to use CSS transitions if they are able to support your animation requirements.
function confirm() {
document.getElementById("wholeshow").classList.add("add");
}
// added
function reset() {
const wholeshow = document.getElementById("wholeshow");
const resetDir = () => { // need to reset the animation direction and remove the `add` class
wholeshow.removeEventListener("animationend", resetDir, true);
wholeshow.style.animationDirection = "normal";
wholeshow.classList.remove("add");
};
wholeshow.addEventListener("animationend", resetDir, true);
wholeshow.style.animationDirection = "reverse";
wholeshow.classList.remove("add");
void wholeshow.offsetWidth; // force rerender
wholeshow.classList.add("add");
}
.confirm-whole {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: grey;
animation: slideIn 0.5s;
}
#keyframes slideIn {
0% {
top: -250px;
height: 0%;
}
99% {
height: 0%;
}
100% {
top: 0px;
height: 100%;
}
}
.add {
display: block;
}
<button onclick="confirm()">Delete</button>
<div id="wholeshow" class="confirm-whole">
<h1 class="confirm">Delete</h1>
<p class="confirm">Are you sure you want to delete ____?</p>
<button class="confirm" onclick="reset()">Delete</button>
<button class="confirm" onclick="cancel()">Cancel</button>
</div>

.show() not working properly (no animation, no further code)

I want a top banner to ease in as soon as the website is loaded. I use JQuery to do that task, but the show() function doesn't work as expected.
$(document).ready(function() {
$('#job').show(2000, function() {
$('#cross').click(function() {
$('#job').hide();
});
});
});
.job-banner {
position: fixed;
top: 0;
width: 100%;
z-index: 1;
background-color: #333;
display: none;
}
.job-banner:hover {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="job" class="job-banner">
<p>...</p>
</div>
But that just shows up the div instantly without any animation and the code that should execute after the animation doesn't work as well. I tried to put an alert inside the code block that should execute after the .show() but nothing.
Is there another way of achieving that or did I do something wrong?
#Sergej Thanks, that did the trick. I just needed to also declare opacity and now I have a css transition instead which is called by JQuery.
So for the CSS:
job-banner {
position: fixed;
top: 0;
width: 100%;
z-index: 1;
background-color: #333;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}
.visible {
visibility: visible;
opacity: 1;
}
And JS:
$(document).ready(function() {
$('#job').addClass('visible');
});

Hard transition of other properties when display property is involved

I want to fade between two differently sized elements within a container overlaying each other. The first element should be faded out, then the container resized and finally the other element faded in.
Here's the related snippet:
var layer1 = document.getElementById("layer1");
var layer2 = document.getElementById("layer2");
function switchLayers() {
layer1.addEventListener("transitionend", function() {
layer2.classList.add("fadein");
});
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px;
overflow: hidden;
}
.layer {
position: relative;
width: 400px;
}
#layer1 {
height: 100px;
float: left;
background-color: blue;
}
#layer2 {
height: 150px;
background-color: red;
display: none;
opacity: 0;
}
#layer1.fadeout {
opacity: 0;
transition: opacity 1s ease-out;
}
#layer2.fadein {
display: block;
opacity: 1;
transition: opacity 1s ease-out;
}
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>
When the second layer's display property is set to block it works as expected, i.e. the opacity is changed from 0 to 1 within a second. Though if it's set to none, the transition suddenly is discrete.
I've tried to set all within the transition value to transition all properties and also tried to include the display property in the transition like this:
transition: display 0s, opacity 1s ease-out;
Though without success. Note that because the container should resize to the size of the currently displayed layer, the visibility property can't be used (as it hides the element but still lets it occupy the space).
How to made this work?
Try using the visibility property instead of display.
For more information regarding the state changes in visibility and display, refer article.
For transitioning the parent height, you have to manually change the height property of the #container. Using display: block & display: none will never transition the parent.
Refer code:
var layer1 = document.getElementById("layer1");
var layer2 = document.getElementById("layer2");
function switchLayers() {
layer1.addEventListener("transitionend", function() {
layer2.classList.add("fadein");
document.getElementById("container").style.height = "170px";
});
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px;
height: 100px;
overflow: hidden;
transition: all 0.5s;
}
.layer {
position: relative;
width: 400px;
}
#layer1 {
height: 100px;
float: left;
background-color: blue;
}
#layer2 {
height: 150px;
background-color: red;
visibility: none;
opacity: 0;
}
#layer1.fadeout {
visibility: none;
opacity: 0;
transition: all 1s ease-out;
}
#layer2.fadein {
visibility: visible;
opacity: 1;
transition: all 1s ease-out;
}
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>
There is no straightforward way. Transitions do not work on display, nor do they work on auto height. So, visibility is a good bet.
Note that because the container should resize to the size of the
currently displayed layer, the visibility property can't be used (as
it hides the element but still lets it occupy the space).
Then, you will need to hack it out. You can make use of min-height. Give a faux min-height to your container, and then apply the height of your layer2 to it once the transition ends. Also, because display on layer2 will block the transition, you need to separate out the classes for display and opacity and space out their application using a zero timeout in between.
Here is a crude idea:
var layer1 = document.getElementById("layer1"),
layer2 = document.getElementById("layer2"),
container = document.getElementById("container"),
h = window.getComputedStyle(layer2).getPropertyValue("height");
container.addEventListener("transitionend", function(e) {
if (e.target.id === 'layer1') {
// apply layer2 height to container min-height
container.style.minHeight = h;
}
if (e.target.id === 'container') {
// First show the layer2
layer2.classList.add("show");
// Then a dummy pause to fadein
setTimeout(function(){
layer2.classList.add("fadein");
}, 0);
}
}, false);
function switchLayers() {
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px; overflow: hidden;
min-height: 1px; /* faux min-height */
transition: min-height 1s linear;
}
.layer { position: relative; width: 400px; }
#layer1 {
height: 100px; float: left;
background-color: blue;
transition: all 1s linear;
}
#layer2 {
height: 150px; background-color: red;
display: none; opacity: 0;
transition: opacity 1s linear;
}
#layer1.fadeout { opacity: 0; }
#layer2.show { display: block; } /* Separate out display */
#layer2.fadein { opacity: 1; } /* Separate out opacity */
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>

Categories