I want to add 2 transition transforms
But I want to start the second transform after the end of the first transform
the element should go to a point slowly and after that it should go to another point
transform: translate(0%, 300%), translate(15%, -136%);
You cannot do this with just a single element using transition because when you put more than one translate within the transform, the transform property on the whole is transitioned and not one by one.
With pure CSS transition using an extra wrapper element:
If you add an extra wrapper element around the actual element and put one of the transforms on the wrapper element you could achieve the effect that you are looking for. It would also produce the exact reverse effect on the hover out (hover the body and hover out in the below snippet).
.wrapper {
position: relative;
height: 100px;
width: 100px;
transition: all 1s 1s;
}
.content {
position: absolute;
height: 100%;
width: 100%;
border: 1px solid;
transition: all 1s;
}
body:hover .content {
transform: translate(15%, -136%);
transition: all 1s 1s;
}
body:hover > .wrapper {
transform: translate(0%, 300%);
transition: all 1s;
}
body {
min-height: 100vh;
}
<div class='wrapper'>
<div class='content'>Some text</div>
</div>
Transition with a bit of JS/jQuery without any extra elements:
If you add an extra wrapper element around the actual element and put one of the transforms on the wrapper element you could achieve the effect that you are looking for. It would also produce the exact reverse effect on the hover out (hover the body and hover out in the below snippet).
$(document).ready(function() {
var isHover; /* variable to track state */
$('body').hover(function() {
isHover = !isHover; /* invert the state */
$('.content').css('transform', 'translate(0%, 300%)');
}, function() {
isHover = !isHover; /* invert the state */
$('.content').css('transform', 'translate(0%, 300%)');
});
$('.content').on('transitionend', function() {
if (isHover) {
$('.content').css('transform', 'translate(0%, 300%) translate(15%, -136%)');
} else {
$('.content').css('transform', 'none');
}
});
});
.content {
height: 100px;
width: 100px;
border: 1px solid;
transition: all 1s;
}
body {
min-height: 100vh;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='content'>Some text</div>
With animation and no extra element:
Using animations this can be done using a single element but the reverse effect is tough to achieve. We would have to write extra code for this and even then it will be complex.
.content {
position: relative;
height: 100px;
width: 100px;
border: 1px solid;
}
body:hover > .content {
animation: move 1s forwards;
}
#keyframes move {
0% {
transform: none;
}
50% {
transform: translate(0%, 300%);
}
100% {
transform: translate(0%, 300%) translate(15%, -136%);
}
}
body {
min-height: 100vh;
}
<div class='content'>Some text</div>
Animations with reverse effect:
Below is a snippet which produces the reverse effect also using CSS animations. But as you can see it is a bit complex. We can do this using a single animation also but it would become more complex.
$(document).ready(function() {
$('body').hover(function() {
$('.content').css('transform', 'none');
$('.content').removeClass('hover-out').addClass('hover-in');
}, function() {
$('.content').css('transform', 'translate(0%, 300%) translate(15%, -136%)'); /* as soon as an animation is removed, the element would snap back to original state, to avoid that we have to add final state via inline style */
$('.content').removeClass('hover-in').addClass('hover-out');
});
});
.content {
height: 100px;
width: 100px;
border: 1px solid;
}
.hover-in {
animation: hover-in 1s forwards;
}
.hover-out {
animation: hover-out 1s forwards;
}
#keyframes hover-in {
0% {
transform: none;
}
50% {
transform: translate(0%, 300%);
}
100% {
transform: translate(0%, 300%) translate(15%, -136%);
}
}
#keyframes hover-out {
0% {
transform: translate(0%, 300%) translate(15%, -136%);
}
50% {
transform: translate(0%, 300%);
}
100% {
transform: none;
}
}
body {
min-height: 100vh;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='content'>Some text</div>
Related
I have an image of a butterfly, something like this.
I am trying to figure out if there is any way to make it look like its wings are opening and closing with a 3D CSS transform/translate or animation, but without having to split the image up into parts (it can be a background image of a div though if that helps).
Yes, using background applied to two elements where each one will show only one half and then you simply rotate both on the Y axis.
.box {
width:300px;
margin:20px;
display:flex;
perspective:500px;
}
.box::before,
.box::after{
content:"";
padding-top:56%; /* ratio based on your image */
flex:1; /* half the main element size */
background-image:url(https://i.imgur.com/DgMoHC5.jpg);
background-size:200% 100%; /* twice bigger than the pseudo element to get half the image*/
animation:left 1s linear infinite alternate;
transform-origin:right;
}
.box::after {
background-position:right; /* get the right part of the image */
animation-name:right;
transform-origin:left;
}
#keyframes left{
to {transform:rotateY(60deg)}
}
#keyframes right{
to {transform:rotateY(-60deg)}
}
<div class="box"></div>
A more realistic animation with some translation:
.box {
width: 300px;
margin: 20px;
display: flex;
perspective: 500px;
}
.box::before,
.box::after {
content: "";
padding-top: 56%;
flex: 1;
background-image: url(https://i.imgur.com/DgMoHC5.jpg);
background-size: 200% 100%;
animation: left 0.5s linear infinite alternate;
transform-origin: right;
}
.box::after {
background-position: right;
animation-name: right;
transform-origin: left;
}
#keyframes left {
from {
transform: translateZ(80px) rotateY(-30deg)
}
to {
transform:translateZ(0px) rotateY(50deg)
}
}
#keyframes right {
from {
transform: translateZ(80px) rotateY(30deg)
}
to {
transform:translateZ(0px) rotateY(-50deg)
}
}
<div class="box"></div>
I'm trying to animate a line that underlines from left to right on 'mouseenter' and then to disappear from left to right on 'mouseleave' instead of the current behaviour where it disappears right to left.
Example of what I'm trying to achieve (but with animations not transitions):
https://jsfiddle.net/1gyksyoa/
I have tried to reverse the 'draw' animation but this doesn't achieve what I'm trying to accomplish.
#keyframes draw-reverse {
100% {
width: 0;
background-color: red;
}
0% {
width: 47px;
background-color: red;
}
}
I have put together this to give a better understanding of the problem;
https://jsfiddle.net/Lq560be9/
Currently, I have the line animating from left to right as desired on 'mouseenter', but on 'mouseleave' it disappears from right to left, whereas I am trying to get the line to also disappear from left to right.
But the problem isn't animation's ability it's the properties that you're animating. Instead of animating the width of an object you should animate its "X" position using translate. (this is much more performant too)
Simply put you need to MOVE the bar from left to center to right instead of trying to scale it.
(there's lots of code here to show the different states the only one you really need to follow is .ex4)
document.querySelector('#animate').addEventListener('mouseenter', function(){
this.classList.toggle('over');
})
document.querySelector('#animate').addEventListener('mouseleave',function(){
this.classList.toggle('out');
})
.example {
margin: 30px auto;
padding: 10px;
background: #dadada;
max-width: 50%;
position: relative;
}
.example:after {
content:'';
position: absolute;
width: 50%;
height: 5px;
background-color: #333;
left:0;
bottom:0;
}
.ex1:after {
transform: translateX(-100%);
}
.ex3:after {
transform: translateX(200%);
}
.ex4 {
overflow: hidden;
}
.ex4:after {
transform: translateX(-100%);
}
.ex4.over:after {
animation: animate-in 1s ease-in-out 1 normal forwards;
}
.ex4.out:after {
animation: animate-out 1s ease-in-out 1 normal forwards;
}
#keyframes animate-in {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
#keyframes animate-out {
0% {
transform: translateX(0);
}
100% {
transform: translateX(200%);
}
}
<div class="example ex1">Object State 1</div>
<div class="example ex2">Object State 2</div>
<div class="example ex3">Object State 3</div>
<div id="animate" class="example ex4">Full example (hover)</div>
As a follow on from above, an alternative solution without using the translate property.
The new animation for mouseleave is;
#keyframes draw-reverse {
0% {
width: 47px;
}
25% {
width: calc(100% - 16px);
}
26% {
width: auto;
right: 8px;
left: 8px;
}
100% {
width: auto;
right: 8px;
left: calc(100% - 8px);
}
}
Full solution can be seen here - https://jsfiddle.net/1wq25tg7/
I am rotating an object with CSS upon hovering, and would like for it to remain in it's new position as you unhover it. I have searched around, but the only thing I could find is css :hover rotate element and keep the new position, which seems to go above and beyond.
Is this effect possible to achieve purely with CSS? I want the icon to remain at the 180 position once you stop hovering.
I used this code:
i.fa.fa-globe:hover {
color: #e9204f;
transition: 0.9s;
transform: rotatey(180deg);
}
Also it's a font-awesome icon if this makes any difference.
Edit - The easy CSS solution for everyone else who needs it (taken from the comments):
.lovernehovermarket i.fa.fa-rocket {
transform: rotate(0deg);
transition: transform 999s;
}
I had a circular icon that I wanted to rotate on every hover, not just the first, and not rotate when un-hovered.
Original
I saw this problem when I had CSS that looked like this
.icon {
transition: transform 0.5s;
}
.icon:hover {
transform: rotate(90deg);
}
Solution
The simple solution was to put the transition inside the :hover psuedo class
.icon:hover {
transition: transform 0.5s;
transform: rotate(90deg);
}
Boom, done!
This works because I was originally setting the transition to be 0.5s by default. In this case, that means both forward and backward. By putting the transition property inside the hover, I have a 0.5s transition when hover is activated, but a 0s transition (the default) when the icon is un-hovered. Having a 0s hover means it just instantly snaps back to position, invisibly to the viewer.
I you want a pure CSS solution, you can set a transtion time to go back to the base state quite high.
It's not for ever, but it's pretty close for most users:
.test {
display: inline-block;
margin: 10px;
background-color: tomato;
transform: rotate(0deg);
transition: transform 999s 999s;
}
.test:hover {
transform: rotate(90deg);
transition: transform 0.5s;
}
<div class="test">TEST</div>
You also need an initial transform state in the regular CSS of your element, so that it can transform between two defined states:
.rotate {
width: 20px;
height: 100px;
background: blue;
transition: 0.9s;
transform: rotate(0deg);
}
.rotate:hover {
transform: rotate(180deg);
}
body {
padding: 100px;
}
<div class="rotate"></div>
If you want to maintain the rotated state, you may have to use a little JQuery to check when the transition ends and change the class so it doesn't revert back to its original state on blur.
This way the div is rotated once and then its class is changed to maintain the rotated state.
$('.rotate').hover(function () {
$(this).addClass("animate");
$(this).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',
function(e) {
$(this).removeClass('rotate').addClass('rotated');
});
});
.rotate {
width: 100px;
height: 100px;
background: gold;
transition-property: transform;
transition-duration: 1.5s;
transition-timing-function: linear;
}
.animate {
animation: rotate 1s linear;
transform: rotate(180deg);
animation-play-state: running;
}
.rotated
{
width: 100px;
height: 100px;
background: gold;
transform: rotate(180deg);
}
body {
padding: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rotate">some text</div>
Use an animation, and apply it using JS event listener, when the element is hovered (mouseover event). When the element is hovered for the 1st time, remove the event listener:
var rect = document.querySelector('.rectangle')
function rotate() {
this.classList.add('rotate');
rect.removeEventListener('mouseover', rotate);
}
rect.addEventListener('mouseover', rotate);
.rectangle {
width: 100px;
height: 100px;
background: gold;
}
.rotate {
animation: rotate 0.5s linear;
}
#keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(180deg);
}
}
body {
padding: 30px;
}
<div class="rectangle"></div>
What worked for me was to put the transform not on hover but on the main css.
not:
#gear {
width: 3vh;
height: auto;
cursor: pointer;
&:hover {
transform: rotate(45deg);
transition: transform 200ms;
}
}
but
#gear {
width: 3vh;
height: auto;
cursor: pointer;
transition: transform 200ms;
&:hover {
transform: rotate(45deg);
}
}
Firefox has a nice behavior when turning off animation in a transition enabled element, it takes the element wherever it is and transition back to original form.
In Chrome it just jumps without transitioning.
Why the inconsistency? Is there any way to replicate in Chrome without using too much JS?
.wrapper {
width: 400px;
height: 200px;
}
.move {
width: 100px;
height: 100px;
position: absolute;
background-color: #f66;
transition: 1s;
cursor: pointer;
}
.move {
animation: move 2s linear infinite;
}
.wrapper:hover .move {
animation: none;
}
#keyframes move {
50% {
transform: translateX(200px);
}
}
<div class="wrapper">
<div class="move"></div>
</div>
$(".spinny").bind("webkitAnimationEnd mozAnimationEnd animationEnd", function(){
$(this).removeClass("spin")
})
$(".spinny").hover(function(){
$(this).addClass("spin");
})
div {
width: 100px;
height: 100px;
background-color: #f66;
transition: 1s;
cursor: pointer;
}
.spin {
animation: spin 1s linear 1;
}
#keyframes spin {
100% {
transform: rotate(180deg);
}
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script><div class="spinny"></div>
Taken from this answer, JS can be used to add and remove classes on hover and animation finish, respectively. jQuery is used in this example, but it is not necessary for the functionality.
EDIT: Now without jQuery, this will play the animation whenever hovered over by remembering the state and checking after the end of every animation.
hover = 0;
s = document.getElementById("spinny");
s.addEventListener("animationend", function(){
s.className = "";
if (hover)
setTimeout(function(){s.className = "spin"},0);
})
s.onmouseover = function(){
s.className = "spin";
hover = 1;
}
s.onmouseout = function(){
hover = 0;
}
div {
width: 100px;
height: 100px;
background-color: #f66;
transition: 1s;
cursor: pointer;
}
.spin {
animation: spin 1s linear 1;
}
#keyframes spin {
100% {
transform: rotate(180deg);
}
}
<div id="spinny"></div>
Add transition along side your transform
.rotate {
width: 200px;
height: 200px;
transform: rotate(0deg);
transition: 0.5s ease all;
background-color: #222;
}
.rotate:hover {
transform: rotate(20deg);
transition: 0.5s ease all;
}
This should prevent it from jumping.
I have an animation, which is taking care of the fading in and out transition on button hover state.
The problem is that the default animation (-webkit-animation: off-state 1s;) is firing off on page load. How do I make it active only after first hover state?
I know how to achieve this using CSS transitions. I am looking for a solution using animation/keyframes.
HTML
<div class="button"></div>
CSS
.button { background: #000; width: 20px; height: 20px; -webkit-animation: off-state 1s; }
.button:hover { -webkit-animation: on-state 1s; }
#-webkit-keyframes on-state {
0% { height: 20px; }
100% { height: 100px; }
}
#-webkit-keyframes off-state {
0% { height: 100px; }
100% { height: 20px; }
}
Demo
As suggested by #Zeaklous, this can be done using JavaScript, e.g. using jQuery:
$('.button').one('mouseout', function () { $(this).addClass('alt-animation'); });
and moving the animation rule to .alt-animation class:
.button { background: #000; width: 20px; height: 20px; }
.button.alt-animation { -webkit-animation: off-state 1s; }
.button:hover { -webkit-animation: on-state 1s; }
Ideally, there should be CSS only alternative.