Chrome CSS transition opacity on hover jumpy issue - css

I'm trying the most simple of opacity transitions in Chrome, but I'm finding that although often it is smooth, sometimes it jumps straight to opacity: 0 or opacity: 1, without transitioning.
Simplified version, just for webkit:
<style type="text/css">
.box{
background-color: #ff0000;
width:100px;
height:100px;
-webkit-transition: opacity 1s;
}
.box:hover{
opacity:0;
}
</style>
<div class="box"></div>
https://jsfiddle.net/bhydbakn/
I find the best way to make it go wrong is to roll over, click, roll off, roll over again, wait for it to reach opacity: 0, then really slowly (pixel by pixel) roll off the image in a downwards direction. When I do this, half the time it will jump straight back to opacity:1 instead of transitioning smoothly.
I'm Chrome 45.0.2454.101 m on Windows 7. Have tested on a colleague's PC and found the same issue.
Here's a video of it going wrong. It works until about half way: http://webm.host/41dce/

Here's an updated code:
<style>
.box {
background-color: #ff0000;
width: 100px;
height: 100px;
opacity: 1;
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
will-change: opacity;
}
.box:hover {
opacity: 0;
}
</style>
<div class="box"></div>
Note the default opacity added to your .box container, an easing function and default hardware acceleration by using a transform declaration.
Note that I cannot reproduce your issue. It might be a browser thing.
UPDATE 2022: I have added CSS prefixes. Omit all -webkit- and -o- if you are building for modern browsers only.

This should fix your issue
$(".box").mouseenter(
function(){
$(this).animate({opacity:'0'},'1000')
});
$(".box").mouseleave(
function() {
$(this).animate({opacity:'1'},'1000')
});
https://jsfiddle.net/bhydbakn/2/

Related

Can simultaneous, expensive CSS transitions be in phase?

There have been questions about the absolute timing precision of CSS transitions and about removing jitter for inexpensive simultaneous transitions. However, the answers didn't give me a clear idea of the relative accuracy of the animation timings (e.g. if two simultaneous animations are "in-phase"), especially when the transitions get expensive.
The effect is most obvious when working with images, like in this fiddle, where the image and container are moving in opposite directions simultaneously trying to keep the image in the same absolute position, but the asynchrony is causing jitter:
/* CSS */
#container {
position:absolute;
width:200px;
height:200px;
left:200px;
overflow:hidden;
background-position:-200px -150px;
-webkit-backface-visiblity:hidden;
-webkit-transition:all 2s ease-in-out;
-moz-transition:all 2s ease-in-out;
-o-transition:all 2s ease-in-out;
transition:all 2s ease-in-out;
}
/* JS */
$(function() {
$('#container').css('left', 0).css('background-position', '0 -150px');
});
Curiously, the jitter is consistently to the right of neutral, which means that the image animation phases are a tad ahead of the container's. It's kind of hard to see, but comparing the offset frames to the stationary final frame, the direction bias is visible.
Is there any way to make sure each step of both transitions are rendered simultaneously?
I think what you are seeing is referred to as Jank.
It happens because of the CSS properties you are trying to animate. Both of these 2 CSS properties i.e. left & background-position trigger paint & compositing operations. Additionally, left property triggers layout as well.
Have a read on the subject of High Performance Animations and also take a look at which CSS properties trigger which operation over at CSS Triggers.
As a solution, you might want to animate translateX instead of left property. The result will be a little better but we would still have background-position to deal with which would keep triggering the heavy operation of re-painting.
I think the best solution, in my humble opinion and I could be completely wrong in approaching it, is to have an img tag inside your #container element, provide the image as its src and remove all the background related properties from your CSS.
And then move it as well using the same translate mentioned above. This way, hopefully, you will get the smoothest of results.
Take a look at this updated fiddle or the snippet below.
Snippet:
$(document).ready(function() {
$('#container').css({
'-webkit-transform': 'translateX(0)',
'-moz-transform': 'translateX(0)',
'-o-transform': 'translateX(0)',
'transform': 'translateX(0)'
});
$('#container > img').css({
'-webkit-transform': 'translate(0px, -150px)',
'-moz-transform': 'translate(0px, -150px)',
'-o-transform': 'translate(0px, -150px)',
'transform': 'translate(0px, -150px)'
});
});
#container {
position: absolute;
width: 200px;
height: 200px;
left: 0px;
overflow: hidden;
-webkit-transform: translateX(200px);
-moz-transform: translateX(200px);
-o-transform: translateX(200px);
transform: translateX(200px);
-webkit-transition: all 2s ease-in-out;
-moz-transition: all 2s ease-in-out;
-o-transition: all 2s ease-in-out;
transition: all 2s ease-in-out;
}
#container > img {
-webkit-transform: translate(-200px, -150px);
-moz-transform: translate(-200px, -150px);
-o-transform: translate(-200px, -150px);
transform: translate(-200px, -150px);
-webkit-transition: all 2s ease-in-out;
-moz-transition: all 2s ease-in-out;
-o-transition: all 2s ease-in-out;
transition: all 2s ease-in-out;
}
body,
html {
margin: 0;
width: 100%;
height: 100%;
}
span {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<span id="container">
<img src="https://images.unsplash.com/photo-1448975750337-b0290d621d6d?crop=entropy&dpr=2&fit=crop&fm=jpg&h=775&ixjsv=2.1.0&ixlib=rb-0.3.5&q=50&w=1450" />
</span>
P.S. As a side note, I am a big fan of GSAP (a JavaScript animation suite of tools). Here is another example using TweenMax (one of the tools from GSAP) which animates x property (a shorthand for translateX within the GSAP world and which also takes care of all the browser prefixes for you behind the scenes) in a more intuitive way using .fromTo() method.

Keyframe CSS animation overwrites hover transition

I am afraid there are similar questions to this but I didn’t found a concrete solution, so I created a fiddle:
http://jsfiddle.net/Garavani/yrnjaf69/2/
<div class= "category_item">
<div class= "cat_button">
<span class="title_cat">TEXT</span>
</div>
</div>
CSS:
.category_item {
position: absolute;
background-color: #999;
top: 100px;
left: 50px;
width: 200px;
height: 200px;
/* seems to be overwriten by animation keyframes */
-webkit-transition: -webkit-transform 0.215s ease-in-out;
transition: transform 0.215s ease-in-out;
cursor: pointer;
}
.category_item:hover {
-webkit-animation-name: easeBack;
animation-name: easeBack;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes easeBack {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
50% {
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
}
100% {
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
}
.cat_button {
position: absolute;
width: 200px;
height: 55px;
bottom: 0;
border: 2px solid #fff;
color: #fff;
-webkit-transition: background 0.215s ease-in-out, border 0.215s ease-in-out, color 0.215s ease-in-out;
transition: background 0.215s ease-in-out, border 0.215s ease-in-out, color 0.215s ease-in-out;
}
.category_item:hover .cat_button {
background: #fff;
border-color: #fff;
color: #511c5b;
}
In this (simplified) animation everything works fine except for when the mouse leaves the entire box. The animation starts from it original state, but abruptly.
The basic transition time (and ease) is ignored because it seems the keyframes have higher importance and overwrite it.
What I need is the keyframe animation triggering AND when the mouse leaves it should turn back to the original state smoothly.
Is there a solution for this
1) in pure CSS
2) maybe with some little javascript only?
Thanks in advance for help and ideas!
EDIT:
After implementing the solution offered kindly by Toni this is the correct fiddle:
http://jsfiddle.net/yrnjaf69/40/
Thanks again Toni!
EDIT 2:
Sadly, yet, there is one question left. The part with the keyframes is not executed on Firefox even though I added all the -moz- vendors, too, in this fiddle:
http://jsfiddle.net/dr6Ld0wL/1/
Why?
PS: As far as I tested for now it works even in Opera (Beta). Only browser resisting is Firefox
EDIT 3:
The correct (working) code is now in this fiddle:
http://jsfiddle.net/dr6Ld0wL/16/
The keyframes also need to be explicitly divided in vendor prefixes. Jesus Christ. Those prefixes…
Here is a jsfiddle that achieves this.
.demo-hover {
position: relative;
margin: 100px;
animation: complexProcessReversed 2s ease-in forwards;
width: 160px;
height: 160px;
background-color: #88d;
}
.demo-hover:hover {
animation: complexProcess 2s ease-in forwards;
width: 100px;
height: 100px;
background-color: #732;
}
#keyframes complexProcess {
/* keyframes */
}
#keyframes complexProcessReversed {
/* keyframes (opposite) */
}
The animation out is assigned in the css in the main class, then the hover state kicks in on hover and css re-applies the original class properties on unhover.
The animation does trigger backwards on page load, so you might like to think of tweaking your animation to take this into account, like this example, pinched from this answer. Alternatively, use javascript (or jquery), like this example where the animations are triggered by adding and removing classes to the target using jquery:
JavaScript
$('.demo-hover').hover(
function() {
// mouse in
$(this).removeClass('forwards--reversed').addClass('forwards');
},
function() {
// mouse out
$(this).removeClass('forwards').addClass('forwards--reversed');
}
);
CSS
.forwards {
animation: complexProcess 2s ease-in forwards;
width: 100px;
height: 100px;
background-color: #732;
}
.forwards--reversed {
animation: complexProcessReversed 2s ease-in forwards;
width: 160px;
height: 160px;
background-color: #88d;
}
Also, I'd use #keyframe or transition. Use transition if you just need a simple even change from n to m but when things are more complex, such as one thing changing evenly over 100% but another thing not starting until 50% off the animation has played, then use a #keyframe
Using both will cause confusion, especially if you're trying to animate the same properties.
Finally css vendor prefixes are required

Css, Html5 zoom in effect , img out of box

Image out of box. It seems that is not the right think I do. If anyone can help I would be glad.
Thank You!
Here You can find Demo
.box {
width:210px;
height:210px;
border-radius:50%;
border:3px solid yellow;
cursor: default;
overflow: hidden;
}
img{
overflow: hidden;
width:210px;
height:210px;
z-index:-1;
display: block;
position: relative;
-webkit-transition: all 0.6s ease-in-out;
-moz-transition: all 0.6s ease-in-out;
-o-transition: all 0.6s ease-in-out;
-ms-transition: all 0.6s ease-in-out;
transition: all 0.6s ease-in-out;
}
.box:hover img{
-webkit-transform: scale(2);
-moz-transform: scale(2);
-o-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
}
It's seems the problem is only on webkit browsers. I make some research after catch that border-radius property crash the scale transition and I found this
overflow:hidden ignored with border-radius and CSS transforms (webkit only)
You have to put -webkit-mask-image: to the parent div to fix that.
-webkit-mask-image: -webkit-radial-gradient(circle, white, black);
http://jsfiddle.net/Jx8xF/16/
Edit: And have you attention, that background-size is expensive operation - see this article on Fix 4. Remove background-size CSS property if it slows down your website
http://kristerkari.github.io/adventures-in-webkit-land/blog/2013/08/30/fixing-a-parallax-scrolling-website-to-run-in-60-fps/
And finally you can see that zoomin the image is more smooth with scale() css transition method than background-size
EDIT2: code update on http://jsfiddle.net/Jx8xF/19/
Tested on Safari 5.1.7, Chrome, Mozilla, IE10, Opera, Opera Next
As you can see the Safari browser is only who have problems after first fix. For him you need to set
-webkit-transform: translateZ(0);
And that is not all. You need to group two layers for the border bug, and wrap it with another div. In code you can see the complete fix in HTML and CSS file.
This effect can be better achieved by removing the img element, and instead using the image as a background on the .box element. Then you use transition on the background-size property.
Here is a working example on CodePen. Example code below.
.box {
-webkit-transition: all 0.4s ease;
width:210px;
height:210px;
border-radius:100%;
border:3px solid yellow;
background: url('http://fc07.deviantart.net/fs71/f/2012/144/b/6/barn_owl_leather_mask_by_teonova_by_teonova-d50xl3v.jpg') center center;
background-size: 100%;
}
.box:hover{
-webkit-transition: all 0.4s ease;
background-size: 150%;
}

How can I make this CSS transition less shaky in Firefox?

Please test the following fiddle in Safari or Chrome as well as Firefox. You will notice that the animation is smooth in Safari, even after the mouse is no longer hovering over the div (when the div has moved past the mouse). In Firefox, however, once the div moves to where the mouse is no longer touching, it begins to move back to its original position, thus causing an unsightly shake. Can I use JavaScript to resolve this issue?
jsFiddle
#object01 {
position:relative;
margin-top:10em;
width:300px;
height:300px;
background-color:red;
border:2px solid black;
transform:rotate(5deg);
-webkit-transform:rotate(5deg);
-moz-transform:rotate(5deg);
-o-transform:rotate(5deg);
-ms-transform:rotate(5deg);
z-index:1000;
transition:all 1s ease;
-webkit-transition:all 1s ease;
-ms-transition:all 1s ease;
-moz-transition:all 1s ease;
-o-transition:all 1s ease;
top:0;
}
#object01:hover {
transform:rotate(0deg);
-webkit-transform:rotate(0deg);
-moz-transform:rotatate(0deg);
-o-transform:rotate(0deg);
-ms-transform:rotate(0deg);
top:-250px;
}
To avoid need to change the markup, you can add a pseudo-element and animate in in the opposite direction, so it will 'hold the active area' when the main element is moved:
#object01:after {
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
-webkit-transition:all 1s ease;
-moz-transition:all 1s ease;
-o-transition:all 1s ease;
transition:all 1s ease;
}
#object01:hover:after {
-webkit-transform: translateY(250px);
-moz-transform: translateY(250px);
-o-transform: translateY(250px);
-ms-transform: translateY(250px));
transform: translateY(250px);
}
(fiddle)
Also, there are several observations that animation has better performance and goes smoother if animating transform: translate(...) than if animating top/left: 1, 2. And it's better if the unprefixed property goes after the prefixed ones (because if the browser supports both prefixed and unprefixed syntax, there are more chances for the prefixed implementation to be buggy than for the unprefixed one). And there is no need to specify -ms-transition since IE9 doesn't understand it, and all shipped versions of IE10 support the unprefixed syntax.

css3 simple animation, when hovering off of the element, it doesn't animate, it just snaps back. How to make it animate smoothly back?

http://jsfiddle.net/nicktheandroid/vX7CV/10/
This is a simple example, but for what I need this for, transition will not work, animation needs to be used.
When hovering the element, the animation smoothly animates the element, when hovering off of the element it snaps back to it's original settings without smoothly animating back.
Is there a way to cause it to animate back to it's settings instead of snapping back like it is?
Animate needs to be used for the :hover event, but when hovering off the element, I could use transition, if this would work, I can't get it to work though.
I have tested you version in Google Chrome and it worked fine for me.
Also added in the Firefox compatibility and that also worked fine for me.
Here is what I have now:
HTML:
<ul>
</li>test</li>
</ul>
CSS:
ul {
background-color:black;
color:white;
width: 100px;
height:100px;
}
#-moz-keyframes flow-down {
0% {
padding-bottom: 0%;
}
100% {
padding-bottom: 30%;
}
}
#-webkit-keyframes flow-down {
0% {
padding-bottom: 0%;
}
100% {
padding-bottom: 30%;
}
}
ul:hover {
-moz-animation-name: flow-down;
-moz-animation-duration: 0.5s;
-moz-animation-timing-function: ease-in-out;
-moz-animation-fill-mode:forwards;
-webkit-animation-name: flow-down;
-webkit-animation-duration: 0.5s;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-fill-mode:forwards;
}
And here is the JSFiddle version just incase:
http://jsfiddle.net/NQ5xk/1/
Hope this helps.
Regards
in firefox, if you have change 'position' or 'z-index' attr during the animation, animation will not run

Resources