Disable JQuery automatic animation - javascript

Sometimes when using JQuery to set the css attribute of an element such as "height", "max-height", it automatically binds animation to the change. Sometimes it is awesome, but it is not always necessary. Is there a way to disable this kind of animation?
Actually what is the exact situation that causes JQuery to automatically bind animations? because I don't always see this kind of behavior. I am not using JQuery-UI.

Perhaps the element you are changing the height of has a css transition property that is responsibe for the animation.
$(function() {
$('.myClass').css('width', '100px');
});
.myClass {
height: 50px;
width: 300px;
background-color: red;
}
.transition {
transition: width 3s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
with transition
<div class="myClass transition">
</div>
without transition
<div class="myClass">
</div>
Borrowing from What is the cleanest way to disable CSS transition effects temporarily?
You can then create a class that will override the transition property and toggle that class
.notransition {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
Note
If you go this route, you may run into the issue of needing to reflow the css
From What is the cleanest way to disable CSS transition effects temporarily? once again:
There are various ways to do this - see here for some. The closest
thing there is to a 'standard' way of doing this is to read the
offsetHeight property of the element.
One solution that actually works, then, is
$someElement.addClass('notransition'); // Disable transitions
doWhateverCssChangesYouWant($someElement);
$someElement[0].offsetHeight; // Trigger a reflow, flushing the CSS
changes $someElement.removeClass('notransition'); // Re-enable
transitions

You can use jQuery.fx.off parameter to define if animation should be used. Read about it here
Also you can modify css values directly without modifying function like
$("#id").css('height', '100px');
instead of
$("#id").height(100);

Related

Why doesn't a css transition fire immediately after display change

TL;DR A css transition on opacity does not work immediately after display change, but works with setTimeout(.., 100). Why?
What do I want?
I want to flash a message for a couple of seconds and then fade it out. Seems pretty basic, right?
What do I have?
Well, here's a jsfiddle, but let me explain in detail.
Say I have a message block
<div id="message" class="message">
Here be dragons
</div>
Which starts hidden but opaque
.message {
opacity: 1;
display: none;
}
Once I've prepared my message I want to show it.
document.getElementById("message").style.display = "block"
Now I want the message to fade out so I added a simple transition on opacity.
.flash {
opacity: 0;
transition: opacity 2s ease-out 1s;
}
Which I apply with the following
document.getElementById("message").classList.add("flash")
What goes wrong?
The message div is shown but it stays invisible as the opacity: 0 immediately applies. Besides, the transitionend event is not firing, which makes me think the transition does not happen at all for some reason. Weird, right?
However, everything's fine once I add the timeout
document.getElementById("message").style.display = "block"
setTimeout(() => (document.getElementById("message").classList.add("flash")), 100)
That works but seems like a totally dirty hack. Why is it like this?
You can see this behaviour on jsfiddle with two buttons aptly named 'Working' and 'Not working';
There are two things that together cause this:
When items have display: none the opacity is ignored (as not relevant). And so when you apply display: block to them they render the provided opacity with the current value without any transition effect.
Changes you apply to the style attribute all apply together at the moment a paint (asynchronous) happens, and so the transition definition comes too late.
First, make sure to set the transition effect definition before the actual application of it, in the message CSS class.
I would then suggest using height instead of display to get the same effect. You would need to switch the border on and off also (through its width):
document.getElementById("working").addEventListener("click" , () => {
document.getElementById("message").classList.add("flash");
})
// reset
document.getElementById("message").addEventListener("transitionend" , () => {
document.getElementById("message").classList.remove("flash")
})
.message {
border: solid 0px;
background: grey;
opacity: 1;
transition: opacity 2s ease-out 1s;
overflow: hidden;
height: 0;
}
.flash {
height: 100%;
opacity: 0;
border-width: 1px
}
<div id="message" class="message">
Here be dragons
</div>
<button id="working"> Working </button>
Why it doesn't work is because you are applying display:block and opactiy: 0 at the same time. When you set the attribute display in css it ignores all transition, there has to be an event in between setting display and transitions. An alternative is using visibility:hidden and visibility:visible instead of display but note that this only hides the element and the element is still present in its position

How to prevent transition to run on page load after height is set with javascript in Safari?

I have a div on a page with liquid height that i want to animate with CSS transitions to collapse/expand.
I set the default height of the div using JS, so if i change the height with CSS, it can easily revert back to the original state. Works fine, the issue is that the height animation will run on page load in Safari. (works fine in Chrome) Any idea how to fix this?
CSS:
div {
background: red;
transition: all 1s cubic-bezier(0.77, 0, 0.175, 1) 0s;
overflow: hidden;
}
div.hide {
height:10px !important;
}
JS:
$div = $('div');
$div.height($div.height());
$div.click(function(){
$div.toggleClass('hide');
});
Demo:
https://jsfiddle.net/69taau5m/1/
It might be a little hacky but you could always apply the transition to your div on click as well.
Did this pretty quick but it works. Check out the fiddle. Could always add some logic to only apply css on the first click.

how to achieve *SMOOTH* fade in and out animation on mobile with jquery and css3?

I know that I can fade in and out with jquery, but on mobile it will be jittery and like low fps or something. After a lot of searching I've found out I can use css3 transition to go to opacitiy 0, but the problem is the element will still have the place to itself. even with visibility:none, it will keep the space it was in. the only way is to use display:none but as I know I can't animate that.
So is there a way to achieve smooth fade in and out animation on mobile with a combination of jquery and css3? or even just one? Thank you.
**EDIT**: Okay the answer for fadeout is working pretty well, now a fade in would be sweet. the problem is I think I have to pul a millisecond delay after ('#id').css('display','block') and before ('#id').css('opactity','1'). don't if it is efficient and all. but it works that way but all my other animations wouldn't work. still am really confused.
You should always try and use CSS3 transitions, instead of jQuery animations. Here I use a CSS3 transition to fade out the .square, and then I wait until the transition has ended to set the display to none.
If you animate an element in jQuery, for example, using fadeOut, you'll see what happens. It basically sets the opacity to 1, and then brings that value down to 0 in tiny increments. This is very inefficient. So it's better to always use CSS3 transitions and animations wherever possible.
Fade out: https://jsfiddle.net/danhaswings/znLL0ws5/1/
Fade in: https://jsfiddle.net/danhaswings/kjgmxa8x/
HTML
<div class="square"></div>
CSS
.square {
width: 100px;
height: 100px;
background-color: red;
transition: opacity 1s ease-in-out;
}
jQuery
var $square = $('.square');
$square.css('opacity', '0');
$square.one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend", function() {
$(this).css('display', 'none');
});
What sort of phone are you testing on to get such slow / jittery animations? Mine seems to work fine for all of the animations that are supported on mobile browsers.
In any case, you can always try to use css keyframes.
Annoyingly, you cannot animate certain attributes (such as display) but it does allow for quite a lot of things including opacity as shown below.
div {
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.to_hide {
-webkit-animation: hide 5s forwards;
animation: hide 2s forwards;
}
#-webkit-keyframes hide {
from {
opacity: 1;
}
40% {
opacity: 0;
}
100% {
position: absolute;
opacity: 0;
}
}
<div class="to_hide"></div>
<div></div>
Keyframes on MDN
Ultimately, on mobiles you should try to avoid using animations as mobile browsers are not optimized for such things. Your website should degrade gracefully in both size, layout, content and also animations.
Should go smoothly if you use jQuery's fadeIn(), which will fade in an element with
display: none
$element.fadeIn();
function show() {
$("#el").fadeIn();
}
#el {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="show()">Show</button>
<div id="el">Hello</div>
Have a look at this article
You should always look to avoid animating properties that will trigger layout or paints, both of which are expensive and may lead to skipped frames.
You should be able to achieve a fade transition combining the opacity and transform properties

Draggable JS Bootstrap modal - performance issues

For a project at work we use Bootstrap Modal windows in JavaScript. We would like to make some of the windows movable, but we are running into performance issues with JQuery.
$("#myModal").draggable({
handle: ".modal-header"
});
Example ,
Source .
In IE9, it works as expected.
In Chrome, horizontal dragging works as expected, and vertical dragging is rather slow but not problematic.
In Firefox, horizontal dragging works as expected, but vertical dragging is extremely slow.
It's strange, because the example window is not graphically heavy and JQuery is supposed to normalize browser behavior. I tried solving this without using JQuery's draggable, but I ran into the same issue.
So I have a couple of questions:
Is the slow performance the fault of the browser, JQuery, Bootstrap or is my code not optimal?
Why is there a difference between horizontal and vertical dragging?
Should I find a workaround, or just avoid Bootstrap altogether for dynamic popups?
Kind regards,
Guido
I found a few ways to fix this.
Adding this to your CSS file will disable the transition effects while the modal is being dragged. It appears however that once the user drags the box the fly in will not occur correctly but rather it will just fade in.
.modal.fade.ui-draggable-dragging {
-moz-transition: none;
-o-transition: none;
-webkit-transition: none;
transition: none;
}
Alternatively adding the following to your CSS file and the nofly class to your model will disable the fly in all together but not the fade in:
.modal.fade.nofly {
top: 10%;
-webkit-transition: opacity 0.3s linear;
-moz-transition: opacity 0.3s linear;
-o-transition: opacity 0.3s linear;
transition: opacity 0.3s linear;
}
I found that at bootstrap 3 I had to override these css properties of the modal dialog:
.modal
{
overflow: hidden;
bottom: auto;
right: auto;
}
.modal-dialog{
margin-right: 0;
margin-left: 0;
}
Fiddle
Full screen demo
This does not exactly answer your questions, but you may try to disable the *-transition properties or decreasing the time value from the specified 0.3s. This is defined in .modal.fade. But this will mess with the initial pop-up animation too. If this is not acceptable, you may use the start event of the draggable widget to apply the new style.
With Bootstrap 3.3 and jQuery UI 1.1 I'm adding a class called "modal-draggable" to the element with the "modal" class.
It binds to the .modal-dialog element inside containers with the .modal-draggable class (unlike some examples here which bind to the actual container).
There is some CSS so scrolling for long dialogs still work across devices of all screen sizes.
CSS:
.modal-draggable .modal-backdrop {
position: fixed;
}
.modal.modal-draggable {
overflow: overflow-y;
}
.modal-draggable .modal-header:hover {
cursor: move;
}
JavaScript:
$(".modal-draggable .modal-dialog").draggable({
handle: ".modal-header"
});
See the JS Fiddle here for a demo:
http://jsfiddle.net/jcosnn6u/3/
NB: So far I have only tested this in Chrome, Firefox and Safari and mobile devices, so can't comment on Internet Explorer compatibility.
I prefer using jqueryui. More detail about draggable API here: http://api.jqueryui.com/draggable/
Although the suggested CSS changes worked for me, I didn't like the dialog being shown on the left initially. Upgrading jquery UI from 1.9 to 1.11 fixed the issue I was seeing

Slide + fade effect using CSS transitions

I'm trying to replicate this effect using CSS effects or transitions.
Using animations I can animate the opacity, but only fadeIn, and the height (which should control the slide) doesn't seem to work at all :(
The closest I've got is by using javascript to set a temporary class on the element I want to animate, and on which I apply the initial opacity. But height doesn't work either. And there seems to be a slight delay on animation start.
Any other ideas?
So I ended up using the solution posted in the question Simon mentioned: With javascript I wrap the element I want to animate within a "wrapper" DIV on which I apply the animation. The wrapper will get its height changed from 0 to the height of the content DIV every time the label is clicked:
fiddle here
I know it requires some javascript, but the idea is to make the animation in CSS, and this is what it does. And if JS is disabled, the toggle will still work...
You can't currently animate on height when one of the heights involved is auto, you have to set two explicit heights. There's an extensive workaround posted as an answer to this similar question.
I made an alteration to your JS Fiddle, I beleive this is what you want; please see it here.
You need to specify a height on the div originally (0) and don't forget overflow:hidden; so that the content doesn't 'spil out' of the div. You will still need jQuery / Javascript however, to toggle a class but it means much less Javascript is required. (I toggled the class "change" which you will see on that fiddle)
input {
display:none;
}
label {
display:inline-block;
}
div {
white-space: pre;
background: #eee;
color: #333;
overflow:hidden;
height:0;
opacity:0;
-moz-transition:height 1s opacity 1s;
-webkit-transition:height 1s opacity 1s;
-o-transition:height 1s opacity 1s;
-ms-transition:height 1s opacity 1s;
transition:height 1s, opacity 1s;
}
.changed {
height:200px;
opacity: 1;
}
I added a few vendor prefixes to the transition CSS propery as I'm not sure what browser you'll be using and I'm on firefox so I need the -moz- prefix lol :)
The only problem I can see with this is that height:auto or height:100% doesn't animate, so you'll need to specify ems or px... If this is going to be a problem (like if the content will be dynamic), I would advise using jQuery for the height animation.

Categories