How to delay a toggleClass event to prevent spam changes? - javascript

I have used the jQueryUI toggleClass delay function however I realised that it creates a delay before the event happens, rather than setting a time before it can be activated again.
I have a few DIVs that switch between classes when they are hovered over using the toggleClass method. However if the cursor is moved quickly over them they keep swapping and it looks buggy. I would like to prevent this by perhaps allowing the toggle to only happen once every 1 second or something.
Is this possible?
$(".landingImage").hover(function () {
var curHeight = this.clientHeight;
$(this).siblings('.imageCover').css("height", curHeight / 1.25);
$(".leftLanding").toggleClass("extraMargin");
$(".rightLanding").toggleClass("extraMargin");
$(this).siblings(".imageCenter").fadeOut(50);
}, function () {
$(this).siblings('.imageCover').css("height", "0px");
$(this).siblings(".imageCenter").fadeIn(600);
});
#landing-images {
position: relative;
width: 100%;
height: auto;
overflow: auto;
margin-top: 6%;
margin-bottom: 5%;
}
.leftLanding {
display: flex;
position: relative;
width: 85%;
margin-left: 3%;
cursor: pointer;
transition: all 0.5s ease;
}
.rightLanding {
display: flex;
position: relative;
width: 85%;
margin-right: 3%;
cursor: pointer;
transition: all 0.5s ease;
}
.extraMargin {
margin-left: 12%;
margin-right: 12%;
}
.landingImage {
position: relative;
display: block;
width: 100%;
height: auto;
z-index: 90;
transition: all 0.5s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="landing-images">
<a href="menu.html"><div class="leftLanding left">
<div class="imageCover">
</div>
<div class="imageCenter">
</div>
<img class="landingImage" src="assets/landingIMG1.png">
</div></a>
<a href="contact.html"><div class="rightLanding right">
<div class="imageCover">
</div>
<div class="imageCenter">
</div>
<img class="landingImage" src="assets/landingIMG3.png">
</div></a>
<a href="burritos.html"><div class="leftLanding left">
<div class="imageCover">
</div>
<div class="imageCenter">
</div>
<img class="landingImage" src="assets/landingIMG2.png">
</div></a>
</div>

If you want to conditionally delay the hover event, you can delay the action using window.setTimeout.
The idea is that you
- set the change to wait for a short while
- set the mouse out behaviour to cancel the pending change.
This code will do something like it:
var delay;
$(".landingImage").hover(function () {
window.setTimeout(doit,250); // queue action
}, function () {
cancel(); // clear hover, if still pending
$(this).siblings('.imageCover').css("height", "0px");
$(this).siblings(".imageCenter").fadeIn(600);
});
function doit() {
var $landingImage=$(".landingImage");
var curHeight = $landingImage.clientHeight;
$landingImage.siblings('.imageCover').css("height", curHeight / 1.25);
$(".leftLanding").toggleClass("extraMargin");
$(".rightLanding").toggleClass("extraMargin");
$landingImage.siblings(".imageCenter").fadeOut(50);
delay=undefined;
}
function cancel() {
if(delay) delay=window.clearTimeout(delay);
}
Because setTimeout is a window method, this is no longer valid. Here I have set a variable to the original element. I generally prefix jQuery variables with $, but that is just a matter of taste.
I haven’t tested in your environment, of course.
As regards doing it the CSS way:
If you want to avoid instant changes, you can add the following to your CSS:
transition-delay: .25s;
or whatever suits you.
transition-delay can also be combined with the general transition property (put it last), but try this first to see how it works.

Related

Why do my css animations become exponentially smaller and eventually stop working?

I am making a small game where a block slides towards the character, and onclick of the main body of the game through a mouse, the character jumps to avoid the block. Whenever I refresh the page, it works normally, but after a few clicks the animation gets smaller and smaller (in the distance is jumps and the time it takes for the animation to complete) and eventually stops working completely. I have included a code snippet so you can see the problem.
let character = document.getElementById('character');
let obstacle = document.getElementById('obstacle');
function jump() {
if (character.classList != 'animate') {
character.classList.add('animate');
}
setInterval(function () {
character.classList.remove('animate');
}, 500);
}
* {
padding: 0;
margin: 0;
}
.game {
height: 200px;
width: 500px;
border: 5px solid black;
}
#keyframes jump{
0%{top: 150px;}
30%{top: 100px;}
70%{top: 100px;}
100%{top: 150;}
}
.character {
height: 50px;
width: 20px;
background-color: red;
position: relative;
top: 150px;
}
.animate {
animation: jump 0.5s;
}
#keyframes block{
0%{left: 480px;}
100%{left: -40px;}
}
.obstacle {
height: 20px;
width: 20px;
background-color: blue;
position: relative;
top: 130px;
left: 480px;
animation: block 2s infinite linear;
}
<!DOCTYPE html>
<html>
<head>
<title>Jumping Game</title>
<link rel="stylesheet" href="jump.css">
</head>
<div>
<body onclick="jump()">
<div class="game">
<div id="character" class="character">
</div>
<div id="obstacle" class="obstacle">
</div>
</div>
</body>
</div>
<script src="jump.js"></script>
</html>
Because you use setInterval, which executes the function provided to it repeatedly in 500ms intervals until you stop it with clearInterval (passing timeout id returned from initial setInterval call).
If you only want to execute the function once after 500ms, use setTimeout instead: https://jsfiddle.net/dp0n8Leh/ (making sure you first clearTimeout for the previous timeout, if you click early enough)
Also, to check if an element has a class, you should use !character.classList.contains('animate') instead of character.classList != 'animate'
just use setTimeout not setInterval to remove the class

HTML/CSS/JS: How to make a smooth transitioning slideshow where one div fades out to reveal the next div?

I'm trying to make a slideshow with smooth transitions on a website a person requested me to make.
For example, when I click next, the current slide (a div with text and buttons) with fade out and the next slide will reveal.
Here is the HTML (edited thanks to a headstarter):
<div id="ssContainer">
<div class="slideshow" id="selected">
<img src="images/slideshow/1.jpg" />
<div class="ssText">
<h1>Welcome to White Grass</h1>
<p>Your complete solution to home building</p>
<button id="portfolioBtn">See Our Portfolio</button>
</div>
</div>
<div class="slideshow">
<img src="images/slideshow/2.jpg" />
<div class="ssText">
<h1>Custom Home Builder</h1>
<p>Customer satisfaction is our top priority</p>
</div>
</div>
<div class="slideshow">
<img src="images/slideshow/3.jpg" />
<div class="ssText">
<h1>Professional & Experienced</h1>
<p>A history of exceptional homes</p>
<button id="contactBtn">Contact Us Now</button>
</div>
</div>
<img id="prev" alt="Previous Slide" onclick="prev();" src="images/slideshow/leftarrow.png"></img>
<img id="next" alt="Next Slide" onclick="next();" src="images/slideshow/rightarrow.png"></img>
</div>
And the CSS:
.slideshow {
display: none;
height: 100%;
position: relative;
transition: display 0.2s;
}
.slideshow img {
max-width: 100%;
max-height: 100vh;
margin: auto;
}
.ssText {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.ssText * {
text-align: center;
}
.ssText h1 {
font-size: 2.5em;
text-transform: uppercase;
background-color: rgba(0, 0, 0, 50%);
padding: 5px;
}
.ssText p {
font-size: 1.1em;
background-color: rgba(0, 0, 0, 50%);
padding: 5px;
}
.ssText button {
position: absolute;
}
#prev, #next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 10px;
transition: background-color 0.2s;
}
#next {
right: 0;
}
#prev:hover, #next:hover {
background-color: rgba(0, 0, 0, 50%);
}
#selected {
display: block !important;
}
#portfolioBtn {
left: 26%;
transform: translateX(26%);
}
#contactBtn {
left: 29%;
transform: translateX(29%);
}
button {
display: block;
border: none;
background-color: #0074c2;
padding: 15px;
font-size: 1em;
font-family: roboto;
color: white;
border-radius: 3px;
transition: background-color 0.2s;
}
Also, the font is Roboto. I added that in the body section of the CSS.
And here are the images:
1.jpg
2.jpg
3.jpg
leftarrow.png (Chevron Left Icon by Icons8)
rightarrow.png (Chevron Right Icon by Icons8)
I got a pretty basic concept of the JavaScript now thanks to an answer:
var slideIndex = 1;
var slides = document.getElementByClassName("slideshow");
function prev() {
if(slideindex < 1) {
slideindex = 3;
}
else {
slideindex--;
}
showSlides();
}
function next() {
if(slideIndex > 3) {
slideIndex = 1;
}
else {
slideIndex++;
}
showSlides();
}
function showSlides() {
if(slideIndex == 1) {
slides[0].id = "selected";
slides[1].id = "";
slides[2].id = "";
}
else if(slideIndex == 2) {
slides[0].id = "";
slides[1].id = "selected";
slides[2].id = "";
}
else if(slideIndex == 3) {
slides[0].id = "";
slides[1].id = "";
slides[2].id = "selected";
}
}
Now, here's the problem:
With the display transition, the images don't transition from block to none.
I even tried messing with the opacity. Gives me the animation but not the slideshow feel.
Changed code for .slideshow and #selected section but reverted:
.slideshow {
display: block;
height: 100%;
position: relative;
opacity: 0;
transition: opacity 0.2s;
}
#selected {
opacity: 1 !important;
}
How do I fix this? Also, tried messing with z-index.
Also, I have to click the previous and next button twice to change from slide 3 to 1 or slide 1 to 3. Weird. Would also want a fix for this.
No jQuery, or any external JS scripts besides my own, please.
Well, this question doesn't comply with Stackoverflow in the way that we expect you to show what you have try and show what you researched. Now you are mostly asking us to write code for you.
Some research and reading will help you get a start on the subject:
how to create transition css javascript
But hey! I've been there too, so, I'll try to give you an example.
DON'T USE THIS CODE
This is only for example purposes and it won't achieve exactly what you are asking for. This code only fades the image background and you are trying to change the whole block of code including the image and text.
The goal behind what follows is only to help you get an idea on how things work.
Let's say that you only want to fade in and fade out your slide. For that, I would use opacity CSS property.
.slideshow img {
max-width: 100%;
max-height: 100vh;
margin: auto;
opacity: 0;
transition: opacity 2s;
}
That said, you will have to add some IDs and your function to your clickable images:
<img id="slide1" src="images/slideshow/1.jpg" />
<img id="slide2" src="images/slideshow/2.jpg" />
<img id="slide3" src="images/slideshow/3.jpg" />
<img id="prev" alt="Previous Slide" onclick="fadeTransition('prev')" src="images/slideshow/leftarrow.png"></img>
<img id="next" alt="Next Slide" onclick="fadeTransition('next')" src="images/slideshow/rightarrow.png"></img>
And then, there is some javacript to help you start with it
var currentSlide = 1;//You need a var that contain the current slide that is show
function fadeTransition(side) {
if ((side === 'prev' && currentSlide === 1) || (side === 'next' && currentSlide === 3)) {return;}
if (side === 'prev') {var newSlide = currentSlide - 1;}
if (side === 'next') {var newSlide = currentSlide + 1;}
document.getElementById('slide'+currentSlide).style.opacity = 0;
document.getElementById('slide'+newSlide).style.opacity = 1;
currentSlide = newSlide;
return;
}
There us a problem with that , on load, all your image will be at opacity 0. You'll have to change the initial state of the first image. At this point, I'll use a class like
.in {
opacity: 1 !important;
}
And into the Javascript, instead of changing style.opacity I would add and remove the in class and adding it into the HTML for load purposes:
<img id="slide1" class="in" src="images/slideshow/1.jpg" />
javascript change class
So now, most of the previous Javascript code blocks are unusable. Keep it in mind that you have to store what the current displayed block is. Restrict your code so the user can't get to a point where he's going to a previous slide when the current slide is the first one.
I hope this will help you in achieving your goal.

CSS transition while moving image to different div using Javascript [duplicate]

This question already has answers here:
Javascript animate CSS float property
(3 answers)
Closed 2 years ago.
I want to move an image from one div to another. And then use the transition property by CSS to make it look good. Here is what I tried:
var image = document.getElementById('some-image');
image.addEventListener("click", function() {
document.getElementById('image-holder2').appendChild(image);
});
div#image-holder1 {
float: left;
}
div#image-holder2 {
float: right;
}
img {
max-width: 50px;
transition: all 1s cubic-bezier(0.85, 0.17, 1, 1);
}
<div id="image-holder1">
<img id="some-image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/1200px-Solid_blue.svg.png">
</div>
<div id="image-holder2">
</div>
As you can see, there is no transition; How can I make the image go to the position smoothly instead of "teleporting"?
You should not specify cubic-bezier inside transaction.
Hope this helps
Good source
var image = document.getElementById('some-image');
image.addEventListener("click", function() {
document.getElementById('image-holder2').appendChild(image);
});
div#image-holder1 {
float: left;
}
div#image-holder2 {
float: right;
}
img {
width: 50px;
transition: width 2s;
transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
}
img:hover{
width: 250px;
}
<div id="image-holder1">
<img id="some-image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/1200px-Solid_blue.svg.png">
</div>
<div id="image-holder2">
</div>
This needs a small trick, First just translate your current element and don't append this until transition completes. In hurry I don't use the exact calculation,
But I advice you not to use left 90.4%, instead of this, use 100%-Image-Width
var image = document.getElementById('some-image');
image.addEventListener("click", function() {
document.getElementById('image-holder1').classList.add('moveNow');
setTimeout(function(){
document.getElementById('image-holder2').appendChild(image);
},1000);
});
div#image-holder1 {
}
.parent {display: flex; justify-content:space-between;}
img {
max-width: 50px;
transition: all 1s cubic-bezier(0.85, 0.17, 1, 1);
}
#image-holder1 {
transition: left 1s;
position: relative;
left: 0;
}
#image-holder1.moveNow {
left: 90.4%;
}
<div class="parent">
<div id="image-holder1">
<img id="some-image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/1200px-Solid_blue.svg.png">
</div>
<div id="image-holder2">
</div>
</div>

CSS Transition Not Working with Javascript [duplicate]

This question already has answers here:
Transitions on the CSS display property
(37 answers)
Closed 3 years ago.
I'm sure that I'm making a rookie mistake here, but I've researched this solution all day, and I can't seem to understand why my code below isn't working.
The use case is a button that opens up a modal box inside a semi-transparent overlay, with the overlay covering everything else on the screen, including the button that opened it. The button is currently opening the modal and overlay just fine, and clicking anywhere outside of the modal box does indeed close it. But I don't understand why my set CSS transition isn't working.
I'm at a loss on this one, so I'd very much appreciate any advice that more seasoned developers can offer. Thank you so much in advance!
Best,
Josh
var modalOverlay = document.getElementById('modalOverlay');
var modalButton = document.getElementById('modalButton');
modalButton.addEventListener('click', openModal);
window.addEventListener('click', closeModal);
function openModal() {
modalOverlay.style.display = "flex";
modalOverlay.style.opacity = "1";
}
function closeModal(event) {
if (event.target == modalOverlay) {
modalOverlay.style.opacity = "0";
modalOverlay.style.display = "none";
}
}
.modal-overlay {
display: none;
opacity: 0;
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
background-color: rgba(0,0,0,0.5);
transition: all 1s ease-in-out;
}
.modal-box {
width: 200px;
height: 200px;
background-color: blue;
}
<button id="modalButton" class="modal-button">Open Modal</button>
<div id="modalOverlay" class="modal-overlay">
<div id="modalBox" class="modal-box"></div>
</div>
display is not a property that can be transitioned. You need to make your animation take multiple steps. When you click the button, the modal should be made flex, but it should still be transparent. Then you need to transition the opacity up to 1 which is what CSS transitions can do.
You need to do the inverse whenever you close the modal. Transition back to opacity 0 and after the transition is done, mark it display: none.
var modalOverlay = document.getElementById('modalOverlay');
var modalButton = document.getElementById('modalButton');
modalButton.addEventListener('click', openModal);
window.addEventListener('click', closeModal);
function openModal() {
// This will cause the browser to know
// that the element is display flex for a frame
requestAnimationFrame(() => {
modalOverlay.classList.add("modal-overlay--open");
// Then when we wait for the next frame
// the browser will now know that it needs
// to do the transition. If we don't make
// them separate actions, the browser
// will try to optimize the layout and skip
// the transition
requestAnimationFrame(() => {
modalOverlay.classList.add("modal-overlay--open-active");
});
});
}
function closeModal(event) {
if (event.target == modalOverlay) {
modalOverlay.classList.remove("modal-overlay--open-active");
setTimeout(() => {
modalOverlay.classList.remove("modal-overlay--open");
}, 1100);
}
}
.modal-overlay {
display: none;
opacity: 0;
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
background-color: rgba(0,0,0,0.5);
transition: all 1s ease-in-out;
}
.modal-overlay.modal-overlay--open {
display: flex;
}
.modal-overlay.modal-overlay--open-active {
opacity: 1;
}
.modal-box {
width: 200px;
height: 200px;
background-color: blue;
}
<button id="modalButton" class="modal-button">Open Modal</button>
<div id="modalOverlay" class="modal-overlay">
<div id="modalBox" class="modal-box"></div>
</div>
Let's draw a little insight from how some other frameworks deal with these kinds of transitions. For example, Vue.js separates its enter/leave transitions into 6 sorts of phases:
Enter: Starting state, added before entry (for you, display: flex and fully transparent)
Enter Active: The transitioning state that sets the transition "target" (opacity towards 1 in your case)
Enter To: What it should be after the transition is complete (we aren't going to bother with this)
Leave: About to start leaving (nothing really needs to change here for us)
Leave Active: Set the target state for your element so that it knows what to transition to (for us, we just remove the class that says opacity: 1)
Leave To: We don't need this either
The main thing that we need to consider is that we need the browser to have the element in the page and "rendered" so that it will consider it for transitioning. That's why we add, in our example, the modal-overlay--open class which makes it flex. We then wait just a second and add the transition target class modal-overlay--open-active which causes the element to actually transition.
Then we do the same thing in reverse: remove modal-overlay--open-active so the browser knows to transition the element back to the "normal" style. We set a timeout to remove the display: flex class after the transition is done. You could use event listeners for this, but it's overkill for such an example.
The display property doesn't play well with transition. Instead, just toggle between opacity 1 and 0.
const modalOverlay = document.getElementById('modalOverlay');
const modalButton = document.getElementById('modalButton');
modalButton.addEventListener('click', openModal);
window.addEventListener('click', closeModal);
function openModal() {
modalOverlay.style.opacity = "1";
modalButton.style.opacity = "0";
}
function closeModal(event) {
if (event.target == modalOverlay) {
modalOverlay.style.opacity = "0";
modalButton.style.opacity = "1";
}
}
.modal-overlay {
opacity: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-overlay,
.modal-button {
transition: opacity 1s ease-in-out;
}
.modal-box {
width: 200px;
height: 200px;
background-color: blue;
}
.modal-button {
position: absolute;
z-index: 2;
}
<button id="modalButton" class="modal-button">Button</button>
<div id="modalOverlay" class="modal-overlay">
<div id="modalBox" class="modal-box"></div>
</div>

I can't get my navigation to change on scroll

I know it is a repeat question, but I am trying to get my navigation bar to change styling using JavaScript/jQuery/CSS by making jQuery add and remove classes depending on the position of the scrollbar, yet with no prevail. I am a huge noob with jQuery. Could someone tell me if these is something wrong with my code. I have searched for hours and I can't find and error. Here is a working example: http://codepen.io/anon/pen/QbWOJv
And here is my code:
// on scroll,
$(window).on('scroll',function(){
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('passed-main');
} else {
$('.nav').removeClass('passed-main');
}
.nav
{
background-color: #000000;
opacity: 0.3;
width: 100%;
height: 40px;
position: fixed;
top: 0;
z-index: 2000;
transition: all 0.3s;
}
.nav.past-main
{
background-color: #ffffff;
opacity: 1;
}
<div class="nav">
</div>
Perhaps the example is something that you want to achieve, and when you try it with your code above, it's not working.
Here's the problem with your code in the snippet:
You forgot to close the function
// on scroll,
$(window).on('scroll',function(){
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('passed-main');
} else {
$('.nav').removeClass('passed-main');
}
}); // You forgot to close the function here
You add/remove class passed-main while in your CSS you're using class selector .nav.past-main
Your window doesn't have any scrollbar, so you need to add this to the CSS to test if it works
body {
height: 1500px;
}
You forgot to include the jQuery in the Snippet.
Here's the working updated snippet
// on scroll,
$(window).on('scroll', function () {
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('past-main');
} else {
$('.nav').removeClass('past-main');
}
});
.nav {
background-color: #000000;
opacity: 0.3;
width: 100%;
height: 40px;
position: fixed;
top: 0;
z-index: 2000;
transition: all 0.3s;
}
.nav.past-main {
background-color: #ffffff;
opacity: 1;
}
body {
height: 1500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div class="nav"></div>

Categories