I've been playing around with animations on hover with pure CSS, applying the animation to element:hover and then the same animation to the regular element in reverse so that when the mouse is moved away the element returns to it's original state, this works fine however any animation that is fired when a user moves their mouse away from an element also runs on page load. I understand why this happens, but I would like to know if there's a way to stop it at all? Preferably not using JS but I don't see how that would be possible really
Current code being used, simple animations on hover:
.image{
animation: hoverout 1s ease-in-out forwards;
}
.image:hover{
animation: hover 1s ease-in-out forwards;
}
#keyframes hover{
0%{
opacity: 0;
}
100%{
opacity: 0.5;
}
}
#keyframes hoverout{
0%{
opacity: 0.5;
}
100%{
opacity: 0;
}
}
You do not need to use animation and keyframes on such a simple hover. Use transition instead. A transition simply transitions between 2 points, in this case between the hover state and the non-hover state.
It would look something like this:
.image {
opacity: 0;
transition: opacity 300ms;
}
.image:hover {
opacity: 1;
}
In this case I set the opacity to transition on hover. You can add more values to this with commas such as transition: opacity 300ms, color 300ms or simplify it by transitioning everything transition: all 300ms, although that will take more performance.
Well, this is a problem.
1) you can use visibility to solve it. Try this:
setTimeout(function(){
$('.image')[0].style.visibility = 'visible';
}, 1000)
element {
visibility: hidden;
}
element:hover {
visibility: visible;
}
$(document).ready(function ($) {
setTimeout(function(){
$('.image')[0].style.visibility = 'visible';
}, 1000)
});
.image-parent {
border: 1px solid;
width: 100px;
height: 100px;
}
.image-parent .image {
width: 100%;
height: 100%;
background: red;
visibility: hidden;
opacity:0;
animation: hoverout 1s ease-in-out;
}
.image-parent:hover .image {
visibility: visible;
animation: hover 1s ease-in-out forwards;
}
#keyframes hover {
0% {
opacity: 0;
}
100% {
opacity: 0.5;
}
}
#keyframes hoverout {
0% {
opacity: 0.5;
}
100% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="image-parent">
<div class="image"></div>
</div>
Here may help u.
2) If you are using animation and keyframe, u can replace them by transition and opacity. Eg:
element {
opacity:0;
transition:opacity 1s, transform 0.5s;
}
element:hover {
opacity:1;
transform : rotateX(90deg);
}
Here may help u.
.image-parent {
border: 1px solid;
width: 100px;
height: 100px;
}
.image{
width: 100%;
height: 100%;
border: 1px solid;
background: red;
opacity: 0;
transition: opacity 1s;
}
.image:hover{
opacity: 0.5;
}
<div class="image-parent">
<div class="image"></div>
</div>
Related
I'm trying to perform a simple CSS transform on :hover — which is obviously an easy task usually but I'm trying to do it on an animating div element. The element is infinitely animating on the Y axis with a simple CSS animation using #keyframes{}, but when I attempt to hover over the element nothing happens.
I can get it to kind of work if I use !important on the hover code, but the transform/scale happens instantly instead of using the 300ms transition property that I've applied to the .box class.
Am I missing something obvious, or is this not possible? Essentially I just want the element to scale on hover using the transition effect and timing, but then resume it's original animation when not hovered. Thanks
.box {
width: 50%;
border: solid 3px #555;
animation: box-move 1s infinite alternate-reverse;
transition: transform 300ms;
}
.box:hover {
transform: scale(1.2);
}
#keyframes box-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-5px);
}
}
<div class="box">I'm a box. I move up and down, but I don't scale nicely when hovered like I should :(</div>
Because you are using transform property on hover and in animation both.
Try this one.
.box {
width: 50%;
border: solid 3px #555;
animation: box-move 1s infinite alternate-reverse;
transition: transform 300ms;
}
.box:hover {
animation: box-move-anim 1s infinite alternate-reverse;
}
#keyframes box-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-5px);
}
}
#keyframes box-move-anim {
0% {
transform: translateY(0) scale(1);
}
100% {
transform: translateY(-5px) scale(1.2);
}
}
Consider another wrapper:
.box {
width: 50%;
animation: box-move 1s infinite alternate-reverse;
}
.box> div {
border: solid 3px #555;
transition: transform 300ms;
transform-origin:top left;
}
.box:hover > div {
transform: scale(1.2);
}
#keyframes box-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-5px);
}
}
<div class="box"><div>I'm a box. I move up and down, but I don't scale nicely when hovered like I should :(</div></div>
Ok, so thanks to your clever and helpful suggestions I managed to find a satisfactory solution. The key for me was using the animation-direction property set to forwards on the :hover. I can't really explain why this works but all I know that it doesn't work properly without it.
I would still ideally like the scale out (hover off) to be as smooth as the scale in (it currently just snaps back), but this will do for my needs.
Thanks again.
.box {
width: 50%;
margin: 1em auto 0 auto;
border: solid 3px #555;
cursor: pointer;
animation: box-move 1s infinite alternate-reverse;
}
.box:hover {
animation: box-move-anim 300ms 1 forwards;
}
#keyframes box-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-5px);
}
}
#keyframes box-move-anim {
0% {
transform: scale(1);
}
100% {
transform: scale(1.2);
}
}
<div class="box">I'm a box that animates up and down, but I now smoothly scale when hovered :)</div>
I have the following div on my html page:
<div class="tooltip">
<span>content</span>
</div>
And the following css script:
.tooltip span {
display:none;
}
.tooltip:hover span {
display:inline;
}
Is there a way to make the span stay visible for more 5 seconds after the mouse is out of the div? The reason I'm trying to do this is because this tooltip has some content inside it such as links.
Here is my attempt!
HTML
<div class="tooltip">
Title
<span> - content</span>
</div>
CSS
.tooltip span {
visibility: hidden;
}
.tooltip:hover span {
visibility: visible;
}
.tooltip span:not(:hover) {
visiblity: hidden;
transition: visibility 5s;
}
JSFiddle: https://jsfiddle.net/mpx3m1v4/
PURE CSS
Sorry, I forgot. Display doesn't get affected by transitions.
Use opacity instead.
Use transitions:
.tooltip span {
opacity: 0;
transition: opacity 0s 1s;
}
.tooltip:hover span {
opacity: 1;
transition: opacity 0s;
}
.tooltip span {
opacity: 0;
transition: opacity 0s 5s;
}
.tooltip:hover span {
opacity: 1;
transition: opacity 0s;
}
<div class="tooltip">
<span>content</span>
</div>
If you want it to fade out, use this:
.tooltip span {
opacity: 0;
transition: opacity 0s 5s;
}
.tooltip:hover span {
opacity: 1;
transition: opacity 0s;
}
.tooltip span {
opacity: 0;
border: 1px solid transparent;
transition: all .4s 4.6s;
}
.tooltip:hover span {
opacity: 1;
border: 1px solid #000;
opacity: 1;
transition: all .4s;
}
<div class="tooltip">
<span>content</span>
</div>
UPDATE use all if you have multiple properties. Note: you generally need have an initial property and a changed property. E.g. See JSFiddle (working)
jQuery solution:
$( ".tooltip" ).mouseover(function() {
$('.tooltip span').show();
setTimeout(function(){
$('.tooltip span').hide('slow', function(){
});// or fade, css display however you'd like.
}, 5000); // set visible time
});
.tooltip span {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tooltip">
tooltip
<span>content</span>
</div>
Pure css. This isn't perfect. Try this.
.tooltip span {
//display:none;
display: block;
}
.tooltip:hover span {
//display:inline;
-webkit-animation: opacity1 0.1s 1 forwards;
animation: opacity1 0.1s 1 forwards;
}
.tooltip:not(:hover) span{
-webkit-animation: opacity0 0.1s 1 forwards;
animation: opacity0 0.1s 1 forwards;
-webkit-animation-delay: 5s;
animation-delay: 5s;
}
#-webkit-keyframes opacity1 {
to {opacity: 1; height: auto; width: auto;}
}
#keyframes opacity1 {
to {opacity: 1; height: auto; width: auto;}
}
#-webkit-keyframes opacity0 {
to {opacity: 0; height: 0; width: 0;}
}
#keyframes opacity0 {
to {opacity: 0; height: 0; width: 0;}
}
How do I activate the CSS animation when the .move class is added to the .box using only CSS? The animation should translate first and when the translate has finished the rotate should begin where the translate ended. Also, how do I make the end state of the animation to be persistent at 100% and reset to 0% when the .move class is removed?
$(".test").click(function(){
$(".box").toggleClass("move")
});
body{
padding: 45px;
}
.test{
margin-top: 15px;
}
.box{
height: 45px;
width: 45px;
background: black;
}
.move{
background: blue;
}
.box{
animation: slide 0.5s, rotate 0.5s;
animation-delay: 0s, 0.5s;
}
#keyframes slide{
100%{
transform: translateX(450px);
}
}
#keyframes rotate{
100%{
transform: rotate(45deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
You can add multiple transforms by placing them together:
transform:translateX(450px) rotate(45deg);
To do this with a key-frame animation, you want to do all stages as a single animation. You will want to apply the animation to the .move class and set animation-fill-mode: forwards to persist the last frame until the class is removed.
$(".test").click(function(){
$(".box").toggleClass("move")
});
body{
padding: 45px;
}
.test{
margin-top: 15px;
}
.box{
height: 45px;
width: 45px;
background: black;
}
.move{
background: blue;
animation: slide 1s;
animation-fill-mode: forwards;
}
#keyframes slide{
50%{
transform: translateX(450px);
}
100%{
transform:translateX(450px) rotate(45deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
That is possible by setting multiple transitions on the element, combined with the transition-delay property.
One note: since each transition has a one to one correspondence to a property, and since you are using the transform property for both the "move" and "rotate" operations, it won't work the way you've written it.
For the "move" operation, I am using margin-left rather than the transform property. You can use any method, as long as it is animatable and doesn't overload a property that you are using for one of the other transitions.
$(".test").click(function(){
$(".box").toggleClass("move")
});
body {
padding: 45px;
}
.test {
margin-top: 15px;
}
.box {
height: 45px;
width: 45px;
background: black;
transition:
margin-left 0.5s,
transform 0.5s;
/* delays for when the .move class was just removed */
transition-delay: 0.5s, 0s;
}
.box.move {
background: blue;
margin-left: 450px;
transform: rotate(45deg);
/* delays for when the .move class was just added */
transition-delay: 0s, 0.5s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
You can also specify the delay directly in the transition shorthand property, like this.
/* transitions for when the .move class was just removed */
transition:
margin-left 0.5s 0.5s,
transform 0.5s 0s;
It seems what you're looking for is a solution based on transition, not animation (unless I misunderstand what you're looking for, in which case please comment):
$(".test").click(function(){
$(".box").toggleClass("move")
});
.test, .box {
margin-top: 15px;
}
.box {
height: 45px;
width: 45px;
background: black;
position: relative;
left: 0;
transition: left 5s, transform 5s linear 5s;
}
.box.move {
background: blue;
left: 450px;
transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<button class="test">Toggle</button>
This may kinda invalidate what you're trying to do, but you're setting transform twice - if you need to target multiple transform properties on one element, you need to do it in one tranform declaration, like this:
.box{
animation: boxStuff 0.5s
}
#keyframes boxStuff{
100%{
transform: translateX(450px) rotate(45deg);;
}
}
Otherwise whichever is further down is just overriding the other. Maybe you can use a margin or something instead of translateX to work around this?
For the other half of your question, you should be able to add this to the .move class to stop on the last animation frame until the move class is removed.
animation-fill-mode: forwards;
If I understood you correctly, this is the result you want.
<a class="test">Toggle</a>
<div class="box"></div>
.box {
width: 200px;
height: 200px;
margin-left: 0;
background: gold;
transform: rotate(0deg);
transition: transform .3s 0s, margin .3s .3s;
}
.move {
margin-left: 50px;
transform: rotate(45deg);
transition: margin .3s 0s, transform .3s .3s;
}
and here's a fiddle https://jsfiddle.net/VilleKoo/owsm0f7h/1/
I have a loader animation in CSS. It rotates 4 divs in a circular fashion. The issue I'm having is that the 4th div (red) is shown initially with no fade in disrupting the flow of the animation (you may have to refresh to see).
What would be the best way to fix this so that the animation's loop is improved?
The Code (https://jsfiddle.net/bduaxvmp/):
.loader {
position: relative;
height: 50px;
width: 50%;
left: 45.5%
}
.loader .bullet {
position: absolute;
padding: 5px;
background: green;
animation: animIn 1s ease-in-out 0s infinite;
}
.loader .bullet:nth-child(1) {
animation-delay: 0.0s;
}
.loader .bullet:nth-child(2) {
animation-delay: 0.15s;
}
.loader .bullet:nth-child(3) {
animation-delay: 0.3s;
}
.loader .bullet:nth-child(4) {
animation-delay: 0.45s;
background: red;
}
#-webkit-keyframes animIn {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100px);
opacity: 0;
}
}
<div class="loader">
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
</div>
Solution:
Set the animation-fill-mode as backwards for the animation. Using this option for the fill mode will make the elements take the state as at the 0% frame during the animation-delay period and hence all the elements will be transparent and in their translated position till the animation actually kicks in.
.loader .bullet {
position: absolute;
padding: 5px;
background: green;
animation: animIn 1s ease-in-out 0s infinite backwards;
}
.loader {
position: relative;
height: 50px;
width: 50%;
left: 45.5%
}
.loader .bullet {
position: absolute;
padding: 5px;
background: green;
animation: animIn 1s ease-in-out 0s infinite backwards;
}
.loader .bullet:nth-child(1) {
animation-delay: 0.0s;
}
.loader .bullet:nth-child(2) {
animation-delay: 0.15s;
}
.loader .bullet:nth-child(3) {
animation-delay: 0.3s;
}
.loader .bullet:nth-child(4) {
animation-delay: 0.45s;
background: red;
}
#-webkit-keyframes animIn {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100px);
opacity: 0;
}
}
#keyframes animIn {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100px);
opacity: 0;
}
}
<div class="loader">
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
</div>
Alternately, you could set the same properties as the 0% frame to the element's default state also and avoid setting animation-fill-mode to backwards but I feel that it is a repetition that could be avoided for this case.
Reason:
The issue I'm having is that the 4th div (red) is shown initially with no fade
Note that the problem is not just the 4th div. Actually the problem is for all the div elements that have the animation delay. Visually only 4th div exhibits the problem because all are absolutely positioned and the 4th div appears on top of the rest due to it being later in the DOM.
If you set a different background color and a higher z-index to the 3rd or 2nd div, you'd see that the same problem happens for them also.
.loader {
position: relative;
height: 50px;
width: 50%;
left: 45.5%
}
.loader .bullet {
position: absolute;
padding: 5px;
background: green;
animation: animIn 1s ease-in-out 1s infinite;
}
.loader .bullet:nth-child(1) {
animation-delay: 0.0s;
}
.loader .bullet:nth-child(2) {
animation-delay: 0.15s;
/*background: blue;
z-index: 4 */
}
.loader .bullet:nth-child(3) {
animation-delay: 0.3s;
background: yellow;
z-index: 2;
}
.loader .bullet:nth-child(4) {
animation-delay: 0.45s;
/*background: red;*/
}
#-webkit-keyframes animIn {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100px);
opacity: 0;
}
}
#keyframes animIn {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateX(100px);
opacity: 0;
}
}
<div class="loader">
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
<div class="bullet"></div>
</div>
The reason this problem happens is because of the way in which animations work. Any animation will continue to hold its default state (specified outside of the animation) till the time the delay timer expires. Setting animation-fill-mode as backwards makes the animation take the state as at first applicable frame even during the delay period and thus avoids the issue.
From MDN:
backwards
The animation will apply the values defined in the first relevant keyframe as soon as it is applied to the target, and retain this during the animation-delay period.
I am trying to give users a "flash" of color when there is a click event. I can get the color to appear in a pleasing fashion using a transition, however I want the color to disappear after .5s, without removing the "active" class. One requirement though is that I cannot use jQuery animations and this must be done in CSS.
Below is the css I am using currently.
.active{
background-color: yellow;
-webkit-transition: background-color .5s linear;
transition: background-color .5s linear;
}
I tried specifying a second value however I do not think this is valid markup as it does not work.
.active{
background-color: yellow;
-webkit-transition: background-color .5s linear, background-color:transparent .5s linear;
transition: background-color .5s linear, background-color:transparent .5s linear;
}
http://jsbin.com/itivum/1/edit
I think this is what you are looking for. The sample is not exact.
$("#go").click(function() {
$("#box").removeClass("demo");
setTimeout(function() {
$("#box").addClass("demo");
}, 1);
});
.container {position: relative;}
#box {
height: 100px;
width: 100px;
background-color: #777;
position: absolute;
left: 5px;
top: 5px;
opacity: 0;
}
#-webkit-keyframes demo {
0% {
background-color: Yellow;
opacity:1;
}
22% {
background-color: Yellow;
}
77% {
background-color: Red;
}
100% {
background-color: #777;
}
}
.demo {
-webkit-animation-name: demo;
-webkit-animation-duration: 900ms;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="go">Go</button>
<div class="container">
<div id="box"></div>
</div>
Hope you will get the solution you are looking for from this.
EDIT :
I have edited your JS Bin.
This will be what you are exactly looking for
http://jsbin.com/imonab/1/edit
I came up with the following based on my own needs. I wanted a flash of color to confirm a user action. The text flashes once when you click on it. It does use jquery to set the class, but not for the animation.
Html:
<span style="background:lightgray" id="id">Click to flash</span>
Js:
$('#id').click(function() {
$('#id').addClass('flash');
setTimeout(function() {
$('#id').removeClass('flash');
}, 500);
});
Css:
.flash {
-webkit-animation-name: flash-animation;
-webkit-animation-duration: 0.3s;
animation-name: flash-animation;
animation-duration: 0.3s;
}
#-webkit-keyframes flash-animation {
from { background: yellow; }
to { background: default; }
}
#keyframes flash-animation {
from { background: yellow; }
to { background: default; }
}
See http://jsfiddle.net/umz8t/3597/
Impressed by Rohith's answer, here is my own JSFiddle demo (with added functionality)
The main part is the CSS (or as I prefer, SCSS):
#-webkit-keyframes quickFlash {
0% {
background-color: yellow;
opacity: 1;
}
100% {
background-color: inherit;
}
}
.quickFlash {
//https://stackoverflow.com/questions/16791851/a-flash-of-color-using-pure-css-transitions
-webkit-animation-name: quickFlash;
-webkit-animation-duration: 1900ms;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease;
-moz-animation-name: quickFlash;
-moz-animation-duration: 1900ms;
-moz-animation-iteration-count: 1;
-moz-animation-timing-function: ease;
}
And I also found it useful to be able to have the class remove itself at the end of the animation (so that I could later add it again if I wanted to see the animations again):
function flashYellow(element) {
element
.addClass("quickFlash")
.on(
"webkitAnimationEnd oanimationend msAnimationEnd animationend",
function() {
console.log("animationend");
$(this)
.delay(500)// Wait for milliseconds.
.queue(function() {
console.log("end of delay");
$(this)
.removeClass("quickFlash")
.dequeue();
});
}
);
}