Given these two examples.
div {
position: absolute;
width: 150px;
height: 40px;
background: orange;
left: 50%;
top: var(--top);
transition: transform 2s;
transform: translateX(-50%);
text-align: center;
line-height: 40px;
font-size: 1.2em;
}
div:hover {
transform: translateX(-50%) rotate(var(--deg));
}
div:nth-child(1) {
--deg: 180deg;
--top: 20%;
}
div:nth-child(2) {
--deg: -180deg;
--top: 40%;
}
div:nth-child(3) {
--deg: 360deg;
--top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>
div {
position: absolute;
width: 150px;
height: 40px;
background: orange;
left: 50%;
top: var(--top);
transform: translateX(-50%);
text-align: center;
line-height: 40px;
font-size: 1.2em;
animation: rotate 2s linear 2s;
}
@keyframes rotate {
to {
transform: translateX(-50%) rotate(var(--deg));
}
}
div:nth-child(1) {
--deg: 180deg;
--top: 20%;
}
div:nth-child(2) {
--deg: -180deg;
--top: 40%;
}
div:nth-child(3) {
--deg: 360deg;
--top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>
As you can see rotate(180deg)
and rotate(-180deg)
act the same and rotate(360deg)
doesn't move at all.
The problem is if you would have it move gradually it acts normally.
div {
position: absolute;
width: 150px;
height: 40px;
background: orange;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
text-align: center;
line-height: 40px;
font-size: 1.2em;
}
div:hover {
animation: rotate 2s linear;
}
@keyframes rotate {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
25% {
transform: translate(-50%, -50%) rotate(45deg);
}
50% {
transform: translate(-50%, -50%) rotate(90deg);
}
75% {
transform: translate(-50%, -50%) rotate(135deg);
}
100% {
transform: translate(-50%, -50%) rotate(180deg);
}
}
<div></div>
The solution that i found is to replace translate(-50%, -50%)
with margins
which is not consistent
div {
position: absolute;
width: 150px;
height: 40px;
background: orange;
left: 50%;
top: var(--top);
transition: transform 2s;
/* Minus half the width, hard coded not a good idea*/
margin: 0 0 0 -75px;
text-align: center;
line-height: 40px;
font-size: 1.2em;
}
div:hover {
transform: rotate(var(--deg));
}
div:nth-child(1) {
--deg: 180deg;
--top: 20%;
}
div:nth-child(2) {
--deg: -180deg;
--top: 40%;
}
div:nth-child(3) {
--deg: 360deg;
--top: 60%;
}
<div>180deg</div>
<div>-180deg</div>
<div>360deg</div>
So The main question is Why that weird behavior is taking place ?
EDIT : Not looking for just a quick answer (as you can see there's two available) but an explanation as well :)
2021: The bug no more occur
It seems a browser bug (at least on Chrome) as it works fine if your try the code on Firefox.
Let refer to the the specification to explain this. Here is all the different cases of how interpolation between transform should work.
In our case, we will consider the last point where we don't have the same number of transform functions and the browser should handle this by adding the identity transform function from the missing list and in our case it should be rotate(0)
.
So technically a transition from translate(-50%)
to translate(-50%) rotate(360deg)
should be the same as a transition from translate(-50%) rotate(0)
to translate(-50%) rotate(360deg)
.
Unless, I am missing something this is for sure a bug as in the case when rotate(360deg)
is used alone, Chrome is handling this fine using the second point (when one value is none
) which is almost the same as the last point.