Once I start animating, on Chrome I get a ripple effect. My circle transform scales up. On Firefox, that exact same animation is ignored for some reason.
$("#animate").click(function() {
$("#square").toggleClass("animate");
$("#fab").toggleClass("ripple");
});
#keyframes ripple {
from {
transform: scale(0)
}
to {
transform: scale(20)
}
}
#square {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid red;
transition: background 0.1s linear 0.6s, transform 1s;
transform: rotate(0deg);
}
#fab {
position: absolute;
width: 56px;
height: 56px;
border-radius: 50%;
background: #4FB5AB;
top: 122px;
right: 0;
transform: scale(1);
transition: transform 1s;
}
.ripple {
animation: ripple 1s 0.5s;
transform: scale(20) !important;
/*Duration - delay */
transition: transform 0s 1s !important;
}
.animate {
transform: rotate(90deg) !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="square">
<div id="fab"></div>
</div>
<br />
<button id="animate">animate</button>
CodePen Demo
Before I start explaining the problem with your code, here is a word of caution - Do not use transitions and animations together. They generally end up causing problems like the one faced here.
When an animation is specified on an element, it will take complete control over the properties that are being animated unless there is a rule with !important setting. If !important setting is used then that rule takes precedence over the animation. (but unfortunately Chrome and Firefox seem to be handling this case differently).
As per W3C Spec:
CSS Animations affect computed property values. During the execution of an animation, the computed value for a property is controlled by the animation. This overrides the value specified in the normal styling system. Animations override all normal rules, but are overriden by !important rules.
emphasis is mine
In your code, there were two problems and they are as follows:
Within .ripple selector, you were specifying the transition-duration as 0s, which means, there is no transition at all and that the change of transform is an instant one. As explained in the W3C Spec, Firefox seems to be (correctly) giving the control to the rule with !important setting (that is, the transform and transition within .ripple selector) and so it transitions the state change immediately after the specified 1s delay+. Chrome lets animation take control and thus produces the effect you are looking for.
Firefox seems to animate the element quicker than Chrome does and so while a duration of 1s is enough for the animation in Chrome, FF needs it to be 2s to be slower and show the effect.
+ - You can further verify this by removing the !important settings on the rules. Once !important is removed, the animation would take control.
$("#animate").click(function() {
$("#square").toggleClass("animate");
$("#fab").toggleClass("ripple");
});
#keyframes ripple {
from {
transform: scale(0)
}
to {
transform: scale(20)
}
}
#square {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid red;
transition: background 0.1s linear 0.6s, transform 1s;
transform: rotate(0deg);
}
#fab {
position: absolute;
width: 56px;
height: 56px;
border-radius: 50%;
background: #4FB5AB;
top: 122px;
right: 0;
transform: scale(1);
transition: transform 1s;
}
#fab.ripple {
animation: ripple 2s 1s;
transform: scale(20);
/*Duration - delay */
transition: transform 1s 1s;
}
#square.animate {
transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="square">
<div id="fab"></div>
</div>
<br />
<button id="animate">animate</button>
Finally, please do not use !important unless it is mandatory. Instead just make the selector more specific. In the snippet, I have made it more specific by using the #id.class format.
Related
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);
}
}
I have a sqare image wich is turned into a circle by using border-radius: 50%; That works quite well so far. ;) But the next step is difficult to do: I want the image to zoom "nearer" by using transform: scale. I mean: I dont want to change the same size of the image, it should stay with the same diameter. But I want to show a small section of the image. The zooming should be activated on :hover and it should be processed during a period of 0.8s
My code works perfectly in Firefox, but in Chrome and Safari it does not. Where are my mistakes?
My HTML:
<div class="hopp_circle_img">
<img src="... alt="" />
</div>
My CSS:
.hopp_circle_img {
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
max-height: 100% !important;
overflow: hidden;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
-o-border-radius: 50%;
border-radius: 50%;
}
.hopp_circle_img img {
transition: all 0.8s;
-moz-transition: all 0.8s;
-webkit-transition: all 0.8s;
-o-transition: all 0.8s;
-ms-transition: all 0.8s;
}
.hopp_circle_img img:hover {
display: block;
z-index: 100;
transform: scale(1.25);
-moz-transform: scale(1.25);
-webkit-transform: scale(1.25);
-o-transform: scale(1.25);
-ms-transform: scale(1.25);
}
The problems:
1) Chrome: The "zoom" works, but during the transition-time (o,8s) the image has sqare borders. After the trasition took place, they are rounded.
2) Safari:
The transition-time is ignored, transition takes place immediately, without "soft" zooming.
3) IE: I did not dare to take a look at IE, if it does not even work in Safari and Chrome. ;)
Thanks for your ideas. I tried many different things, none of them worked.
Raphael
With Harry's suggestion to fix the square, this one should work in Safari as well.
First, prefixed properties should be before unprefixed, second, don't use all as in
transition: all ...
name the properties to be transitioned, in this case
transition: transform 0.8s
Note, you need to add back the rest of the prefixed properties
.hopp_circle_img {
position: relative; /* new property added */
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
max-height: 100% !important;
overflow: hidden;
-webkit-border-radius: 50%;
border-radius: 50%;
z-index: 0; /* new property added */
}
.hopp_circle_img img {
-webkit-transition: transform 0.8s; /* re-ordered property, named */
transition: transform 0.8s; /* what to be transitioned */
}
.hopp_circle_img img:hover {
display: block;
z-index: 100;
-webkit-transform: scale(1.25);
transform: scale(1.25);
}
<div class="hopp_circle_img">
<img src="http://lorempixel.com/400/400/nature/1" alt="" />
</div>
OK, I have a first success:
Changing .hopp_circle_img img:hover into .hopp_circle_img:hover fixed the problem in Safari. But it still remains in Chrome.
What fixed this issue for me was:
.hopp_circle_img {
transform: scale(.99);
}
I have a custom checkbox that is filled with transitions for border, color, etc. as well as for 3d transformation to flip it over. If the checkbox is unchecked it looks fine and transitions nicely between states, however, if the checkbox is given the checked attribute on dom load then it has to spin into place and the checkbox is visible on the backface.
NOTE: Although I link the JsFiddle so you can see the code the issue is not happening in the fiddle. It only happens if the style is linked via style sheet.
https://jsfiddle.net/tj2djeej/
/* Radio & Checkbox */
input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
-webkit-transform-style: preserve-3d;
-webkit-appearance: none;
-webkit-transform: rotatey(0deg);
-webkit-perspective: 800;
-webkit-transform-style: preserve-3d;
box-sizing: border-box;
position: relative;
outline: none;
width: 26px;
height: 26px;
border: 3px solid #C15649;
cursor: pointer;
}
input.flipCheckbox:checked {
-webkit-transform: rotatey(180deg);
}
input.flipCheckbox:after {
-webkit-transform: rotatey(-180deg);
-webkit-transition: color 0s linear .25s, -webkit-text-stroke-color 0s linear .25s;
-webkit-text-stroke-color: transparent;
cursor: pointer;
line-height: 26px;
font-size: 14px;
width: 26px;
height: 26px;
position: absolute;
z-index: 1;
top: -3px;
left: -3px;
color: transparent;
text-align: center;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: transparent;
}
input.flipCheckbox:checked:after {
color: #C15649;
-webkit-text-stroke-color: #C15649;
}
input.flipCheckbox:after {
content: "\2713";
}
<input type="checkbox" class="flipCheckbox" />
<input type="checkbox" checked class="flipCheckbox" />
If you just want to hide the checkmark when unchecked, there's backface-visibility: hidden.
input.flipCheckbox:after {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
This should simplify a lot of things for you. For one, you no longer need to animate the checkmark's color from transparent.
The :focus and :hover pseudo-classes should work well for your needs. Just move your transition rule from input.flipCheckbox to a new rule-set:
input.flipCheckbox:focus, body:hover input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
}
Since the checkbox is not focused on page load the transition doesn't occur, yet when the user checks the check box it gains focus allowing the transition to occur. The only downside is if the checkbox uses focus before the animation completes. Like when a user is using just the keyboard and tabs away too quickly. That's where :hover steps in. Since :hover is applied to body (html or any other parent would work as well) as long as the cursor is on the page, the transition still occurs.
You could just use one or the other, but the two together covers everything except if the cursor is off the page and the user tabs away too quickly.
As you said, the issues doesn't occur in online editors, but here's the full code anyways.
input.flipCheckbox {
-webkit-transform-style: preserve-3d;
-webkit-appearance:none;
-webkit-transform: rotatey(0deg);
-webkit-perspective: 800;
-webkit-transform-style: preserve-3d;
box-sizing: border-box;
position:relative;
outline:none;
width: 26px;
height:26px;
border: 3px solid #C15649;
cursor: pointer;
}
input.flipCheckbox:focus, body:hover input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
}
input.flipCheckbox:checked {
-webkit-transform: rotatey(180deg);
}
input.flipCheckbox:after {
-webkit-transform: rotatey(-180deg);
-webkit-transition: color 0s linear .25s, -webkit-text-stroke-color 0s linear .25s;
-webkit-text-stroke-color: transparent;
cursor: pointer;
line-height:26px;
font-size:14px;
width:26px;
height:26px;
position: absolute;
z-index: 1;
top:-3px;
left:-3px;
color:transparent;
text-align: center;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: transparent;
}
input.flipCheckbox:checked:after {
color: #C15649;
-webkit-text-stroke-color: #C15649;
}
input.flipCheckbox:after {
content:"\2713";
}
<input type="checkbox" class="flipCheckbox"/>
<input type="checkbox" checked class="flipCheckbox"/>
You could set an animation on the element, that changes the element state at its own speed.
The trick here is to get an animation that is:
Not really an animation, in the sense that there is no change in the property value. This is achieved setting 2 different keyframes with the same value.
The same animation for both the checked and the unchecked states. If we change the animation name, the animation will be replayed every time that we change states. To allow for this, I set an animation that has 2 different parts, one that has the element rotated and another with the element unrotated. We use one part or the other changing the direction from normal to reverse. And setting an initial delay that makes it use only the last half.
I Have tried to reproduce your scenario via javascript, redenring the elemnt and setting the check state afterwards. I don't know for sure if this is equivalent to it.
On the snippet press the button and it will alternate rendering the element from scratch, once in the checked state and another in the unchecked
var ele;
var checked = true;
function reload() {
var oldele = document.getElementById("test");
ele = oldele.cloneNode(true);
oldele.parentNode.replaceChild(ele, oldele);
setTimeout(check, 1);
}
function check() {
ele.checked = checked;
checked = !checked;
}
.test {
width: 100px;
height: 100px;
transition: transform 0.5s;
transform: rotateY(180deg);
animation-name: still;
animation-duration: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-delay: -0.11s;
}
button {
margin: 20px;
}
.test:checked {
transform: rotateY(0deg);
animation-direction: reverse;
}
input {
animation-name: "";
}
#keyframes still {
from, 49.9% {
transform: rotateY(0deg);
}
50%,
to {
transform: rotateY(180deg);
}
}
<input type="checkbox" class="test" id="test" />
<button onclick="reload()">Load</button>
It seems to be a bug with Chrome/Webkit. At least in my version of Chrome and Safari, the behavior I have is the following:
Without any script tag in the html or a script tag before the css link or a completely empty script tag, and without any input elements, there is no transition happening on div, or other non input elements.
Without any script tag in the html or a script tag before the css link or a completely empty script tag, as soon as there's one input element (whichever type), then all elements that have a style that doesn't match default value are transitioned.
If you add a script tag after the css link with at least a space inside it, then no transition occurs on load on any element.
So it looks like input elements trigger some kind of layout refresh, that strangely does not occur when a script is there. Maybe simply because of a delay somewhere in the parsing, or a condition that is wrongly set somewhere. At least this is the behavior I have with Chrome and Safari.
So you can simply add :
<script> </script> <!-- the space is important -->
after you link element, and you won't get the behavior you describe. It is not a css solution, but the problem doesn't seem to be with your CSS, so I'm posting it anyway.
Does it need to connect to an external style sheet? You may be able to get away with a <style> tag in the html file itself. If not, make sure that the <link> is in the header so that it loads first, enabling the CSS to be applied as soon as the page loads.
Bit hackish but satisfies the css only requirement.
Do a one time "animation" on the elements with checked attribute:
input.flipCheckbox[checked]{
animation-name: fakeRotate;
animation-duration: 0.1s;
animation-iteration-count: 1;
}
#keyframes fakeRotate {
from {
transform: rotatey(180deg);
}
to {
transform: rotatey(180deg);
}
}
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
Is it possible to animate (using transitions) only one type of css transform?
I have css:
cell{
transform: scale(2) translate(100px, 200px);
transition: All 0.25s;
}
Now, I want only scale to be animated.
In this case I could use position:absolute and left/right properties but I far as I remember, translate() is much better in performance.
I would also like to avoid using additional html elements.
Fiddle: http://jsfiddle.net/6UE28/2/
No! you cannot use transition only for certain value of transform like scale(2).
One possible solution would be as follows: (sorry, you have to use additional html)
HTML
<div class="scale">
<div class="translate">
Hello World
</div>
</div>
CSS
div.scale:hover {
transform: scale(2);
transition: transform 0.25s;
}
div.scale:hover div.translate {
transform: translate(100px,200px);
}
Yes! You separate it into two selectors, one of them with transition: none, then trigger CSS reflow in between to apply the change (otherwise it will be considered as one change and will transition).
var el = document.getElementById('el');
el.addEventListener('click', function() {
el.classList.add('enlarged');
el.offsetHeight; /* CSS reflow */
el.classList.add('moved');
});
#el { width: 20px; height: 20px; background-color: black; border-radius: 100%; }
#el.enlarged { transform: scale(2); transition: none; }
#el.moved { transform: scale(2) translate(100px); transition: transform 3s; }
<div id="el"></div>
Yes, why not. In order to do that, you have to actually use only one transform.
This is what is confusing you: you don't apply transform on the element itself. You apply that to the change-state (by means of a pseudo class like :hover or another class using styles that you want in the changed state). Please see #David's comment on your question. You change state for only that property which you want to change and that will animate.
So, effectively you change them selectively based on changed-state.
Solution 1: Using Javascript (based on the fiddle you provided in your question)
Demo: http://jsfiddle.net/abhitalks/6UE28/4/
Relevant CSS:
div{
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
/* do NOT specify transforms here */
}
Relevant jQuery:
$('...').click(function(){
$("#trgt").css({
"-webkit-transform": "scale(0.5)"
});
});
// OR
$('...').click(function(){
$("#trgt").css({
"-webkit-transform": "translate(100px, 100px)"
});
});
// OR
$('...').click(function(){
$("#trgt").css({
"-webkit-transform": "scale(0.5) translate(100px, 100px)"
});
});
Solution 2: Using CSS Only
Demo 2: http://jsfiddle.net/abhitalks/4pPSw/1/
Relevant CSS:
div{
-webkit-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
/* do NOT specify transforms here */
}
div:hover {
-webkit-transform: scale(0.5);
}
/* OR */
div:hover {
-webkit-transform: translate(100px, 100px);
}
/* OR */
div:hover {
-webkit-transform: scale(0.5) translate(100px, 100px);
}
Yes! Now you can, because translate, scale and rotate have been moved to a separate css properties! (MDN: translate, scale, rotate)
So now you can do:
div{
scale: 1;
translate: 0;
transition: scale 0.4s;
}
div.clicked{
scale: 2;
translate: 100px 200px;
}
Example: http://jsfiddle.net/bjkdthr5/1/ (only scale will animate)
Instead of forcing a reflow, you can instead use setTimeout.
var el = document.getElementById('el');
el.addEventListener('click', function() {
el.classList.add('enlarged');
setTimeout(function() {el.classList.add('moved');})
});
#el { width: 20px; height: 20px; background-color: black; border-radius: 100%; }
#el.enlarged { transform: scale(2); transition: none; }
#el.moved { transform: scale(2) translate(100px); transition: transform 3s; }
<div id="el"></div>