Why does adding a rotation animation offset my image? [duplicate] - html

This question already has an answer here:
How to keep origin in center of image in scale animation?
(1 answer)
Closed 1 year ago.
Im trying to make a logo that spins, but once the animation is being added, it jumps a down and i can't figure out why. I'm just adding -webkit-animation: rotation 5s infinite linear; and not adjusting the position at all.
Here's a live version of it, you can click the logo after the initial animation to add the rotate class. Any ideas how to make it stay in place?
const EL_logo = document.querySelector(".permanent-logo");
EL_logo.addEventListener("click", () => {
EL_logo.classList.add("rotate-logo");
});
.permanent-logo {
position: relative;
left: 50%;
transform: translate(-50%, -50%);
top: 70px;
width: 120px;
}
.rotate-logo {
animation: rotation 5s infinite linear;
}
#keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
<div class="initial-overlay">
<div class="logo-container">
<img class="permanent-logo" src="https://i.stack.imgur.com/g2LtV.png" alt="logo">
</div>
</div>

If your element has already a non animated transform applied transform: translate(-50%, -50%), the animation keyframes should also consider that initial transformations - because later transformations are not added on top, composited over the existing ones.
You should repeat them transform: translate(-50%, -50%) rotate(0deg);:
const EL_logo = document.querySelector(".permanent-logo");
EL_logo.addEventListener("click", () => {
EL_logo.classList.add("rotate-logo");
});
.permanent-logo {
position: relative;
left: 50%;
transform: translate(-50%, -50%);
top: 70px;
width: 120px;
}
.rotate-logo {
animation: rotation 5s infinite linear;
}
#keyframes rotation {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(359deg);
}
}
<div class="initial-overlay">
<div class="logo-container">
<img class="permanent-logo" src="https://i.stack.imgur.com/g2LtV.png" alt="logo">
</div>
</div>

Related

Why does 'transform:rotate(Xdeg)' cause the animation to stop?

I tried to rotate an animated font arrow when the window reached a min/max size, but when the rotate takes place the animation stops, also just for testing I tried replacing transform: rotate(90deg) to transform: rotate(0deg) which maintains the same arrow's direction but it causes to stop the animation too. The issue is with transform: rotate() and it can be easily tested by inspecting the element and activating/deactivating it in the browsers developer tools.
An easy way to bypass this can be using two <p> each one with an arrow in different direction and with vertical and horizontal animation each, and using display: none; to alternate between them when the min/max size switches, but what I want is to know why this is happening and how to solve this using this approach
.text-center {
text-align: center;
}
.lnr-x3 {
font-size: 2.4rem;
}
#media (max-width: 991px) {
#catalogArrow_h {
transform: rotate(90deg) !important;
transform-origin: center !important;
}
}
.animated-h {
text-decoration: none;
outline-style: none;
-webkit-animation: movingHorizontally 1.7s ease-in-out infinite;
animation: movingHorizontally 1.7s ease-in-out infinite;
}
#keyframes movingHorizontally {
0% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
50% {
transform: translateX(-10px);
-webkit-transform: translateX(-10px);
}
100% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
}
#-webkit-keyframes movingHorizontally {
0% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
50% {
transform: translateX(-10px);
-webkit-transform: translateX(-10px);
}
100% {
transform: translateX(0px);
-webkit-transform: translateX(0px);
}
}
<!-- Font Icons -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" type="text/css">
<link rel="stylesheet" href="https://cdn.linearicons.com/free/1.0.0/icon-font.min.css">
<div class="col-12">
<p class="text-center pt-3 px-5">
<span id="catalogArrow_h" class="lnr lnr-x3 lnr-arrow-right fas animated-h"></span>
</p>
</div>
Why does this happen
The transform property is "shared" for many transform functions and css doesn't combine any property's values.
Because your animation is made with transform: translateX(..), adding transform: rotate(..) will overwrite the property's value, not combine them. I.e. the resulting style is transform: rotate(..), not transform: translateX(..) rotate(..).
It would be the same if you were animating the box-shadow and then wanted an inset box-shadow too, it would overwrite one with the other. Or more simply - if you have .box { color: red; color: blue; } css will choose the last value (blue) to apply to the color property.
If there were css properties rotate: 90deg and translate: 4px (there are but not widely supported), then your animation would work, because the translate animation would be applying to a different property than the rotation, not overwriting one that is essentially shared amongst many transform functions.
Ways around it
There are many ways around this problem.
You can set the translate or rotate on the parent element
<div class="rotate-90">
<span class="translate-animate"></span>
</div>
You can add the rotate to your translate animation properties:
#keyframes movingHorizontallyRotated {
0%, 100% { transform: translateX(0px) rotate(90deg); }
50% { transform: translateX(-10px) rotate(90deg); }
}
You can animate a different property to translate the element:
#keyframes movingHorizontally {
0%, 100% { padding: 5px 10px 5px 0px; }
50% { padding: 5px 0px 5px 10px; }
}
You can use/make an already rotated arrow if your framework/ assets provides one.

Rotate twice from two origin

I have a css div I want first to rotate at 180deg from the center origin and then rotate from -45deg from the "new" bottom left corner.
But I don't manage to apply two different rotations
https://imgur.com/a/9GSToEx -> So you can better understand
CSS
.player1{
background-color: blueviolet;
transform-origin: center;
transform: rotate(180deg);
transform-origin: bottom left;
transform: rotate(45deg);
}
HTML
<div class="player1">
<div class="questionSpace"></div>
</div>
Thank you ^^
This can be a bit tricky because of the need to move the origin and the rotations not being additive.
A fairly straightforward way of getting round the problem is to enclose the element in a parent whose sole purpose is to allow an independent 180deg rotation.
This snippet colors the player1 element with a linear-gradient so it can be seen that the 180deg rotation has taken place.
.player1container {
display: inline-block;
transform: rotate(180deg);
margin: 20vmin;
/* added just for demo */
}
.player1 {
background-color: blueviolet;
width: 20vmin;
height: 10vmin;
background-image: linear-gradient(red, blue);
transform: rotate(-45deg);
transform-origin: top right;
}
<div class="player1container">
<div class="player1">
<div class="questionSpace"></div>
</div>
</div>
Hmm. Your code is wrong, because this rules have conflict and last rule have more priority;
transform: rotate(180deg);
...
transform: rotate(45deg);
You need to use #keyframes
for example:
#rotate {
0% {
transform: rotate(0);
}
50% {
transform: rotate(180deg);
}
100% {
transform-origin: left;
transform: rotate(45deg);
}
}
and then you need to use animation: rotate;

Transform: translate Doesn't work in React / SASS [duplicate]

This question already has an answer here:
How to keep origin in center of image in scale animation?
(1 answer)
Closed 1 year ago.
I couldn't find a solution for this simple problem, I changed the display to flex and block, that didn't work either. It works on parent element. But I guess there is something I can't see on this code.
.planets {
display: flex;
height: 100vh;
}
.pluton-orbit {
display: inline-block;
width: 70rem;
height: 70rem;
border: 1px solid rgba(0, 0, 0, 0.219);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50% , -50%);
z-index: 4;
animation: Rotation 5s linear infinite;
}
#keyframes Rotation {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
the transform here, doesn't work. I know how to center, my question is why doesn't the transform property work. this is react with Sass by the way. Everything else works in the code, just the transform has this weird problem. here is the component.
import React from "react";
const Planets: React.FC = () => {
return (
<div className="planets">
<div className="pluton-orbit">
<div className="pluton"></div>
</div>
<div className="neptun-orbit">
<div className="neptun"></div>
</div>
</div>
);
};
export default Planets;
It's because the animation is overriding the transform property. This is one limitation of transform. a solution is to add the translate(-50%, -50%) to the animation keyframes.
#keyframes Rotation {
from {
transform: translate(-50%, -50%) rotate(0);
}
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}

Preserve CSS transform property after removing the class

Is it possible to preserve a CSS property (including variables) after removing a class that modifies them ?
The problem is in the code below.
I want to preserve the transform property of the cyan box after removing the class animation-slide-to-left that slides the box to the left.
That is because when removing that animation-slide-to-left and adding the class animation-slide-to-right class, I want that new animation to start from where the old one ended.
But the problem is when removing animation-slide-to-left the transform property resets and becomes equal to Its old value before adding that class.
Note: I don't want to hard code the transform property at 0%, because there are a lot of animations, and I am searching for a way that automatically solve the problem without JAVASCRIPT.
(expand the snippet result to full page too see the example)
const box = document.querySelector (".animated");
function leftclicked (){
box.classList.remove ("animation-slide-to-right");
box.classList.add ("animation-slide-to-left");
}
function rightclicked (){
box.classList.remove ("animation-slide-to-left");
box.classList.add ("animation-slide-to-right");
}
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.animated {
animation-duration: 0.5s;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
.animation-slide-to-left {
animation-name: slide-to-left;
}
.animation-slide-to-right {
animation-name: slide-to-right;
}
#keyframes slide-to-left {
100%{
transform: translate(-150%, -50%);
}
}
#keyframes slide-to-right {
100%{
transform: translate(50%, -50%);
}
}
<div class="center" style="width:300px; height: 300px; background-color: red;">
<div class="center animated" style="width: 50%; height: 50%; background-color:cyan;">
</div>
<button style="float:left;" onclick="leftclicked()">LEFT</button>
<button style="float:right;" onclick="rightclicked()">RIGHT</button>
</div>
You can set the starting position for each time you click on the buttons LEFT and RIGHT in the CSS keyframes, so that when the button is on the left side and click on the RIGHT button, it first sets the position to the left side (0%) before it animates to the right (100%) and vice-versa. This way it doesn't reset back to the center when clicking the buttons.
const box = document.querySelector (".animated");
function leftclicked (){
box.style.transform = 'translate(50%, -50%)';
box.classList.remove ("animation-slide-to-right");
box.classList.add ("animation-slide-to-left");
}
function rightclicked (){
box.style.transform = 'translate(-150%, -50%)';
box.classList.remove ("animation-slide-to-left");
box.classList.add ("animation-slide-to-right");
}
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.animated {
animation-duration: 0.5s;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
.animation-slide-to-left {
animation-name: slide-to-left;
}
.animation-slide-to-right {
animation-name: slide-to-right;
}
#keyframes slide-to-left {
100%{
transform: translate(-150%, -50%);
}
}
#keyframes slide-to-right {
100%{
transform: translate(50%, -50%);
}
}
<div class="center" style="width:300px; height: 300px; background-color: red;">
<div class="center animated" style="width: 50%; height: 50%; background-color:cyan;">
</div>
<button style="float:left;" onclick="leftclicked()">LEFT</button>
<button style="float:right;" onclick="rightclicked()">RIGHT</button>
</div>
Well It turns out that it is unnecessary to create such behaviour without JavaScript.
Because if a CSS class is being replaced at runtime, we are already using JavaScript.
So the solution is to set the transform property in JavaScript after removing the old class and before adding the new class

Cube rotation with css

I am having a bit of an issue with rotation of a cube. I want to make it cross-browser so I am transforming every side of the cube. When I am rotating from left to right the sides align perfectly on all browsers Chrome, Firefox and IE, BUT when the cube is rotated from top to bottom, the sides align only on Chrome (If I make the animation slower on Chrome the sides are broken the same way as the other browsers, so I think working properly is a bug :D). I have provided an example on jsfiddle:
http://jsfiddle.net/0n9bnxe5/
HTML:
<div class="flip-card-content">
<div class="flip-card-side-a" style="background:red">
FRONT
</div>
<div class="flip-card-side-b" style="background:green">
BACK
</div>
<div class="flip-card-side-c" style="background:aqua">
LEFT
</div>
</div>
<button id="button">Flip-top</button>
<button id="button2">Filp-right</button>
CSS:
.flip-card-content {
position: relative;
margin: 100px;
width: 200px;
height: 200px;
transform-style: preserve-3d;
perspective:1000px;
}
.flip-card-side-a,
.flip-card-side-b,
.flip-card-side-c{
width: 100%;
position: absolute;
height: 100%;
backface-visibility: hidden;
transform-origin:50% 50% 0px;
transition: all .5s ease-in-out;
}
.flip-card-side-a {
transform: rotateY(0deg) translateZ(100px);
z-index: 1;
}
.flip-card-side-b {
transform: rotateX(90deg) translateZ(100px);
}
.flip-card-side-c {
transform: rotateY(-90deg) translateZ(100px);
}
.flip .flip-card-side-a {
transform: rotateX(-90deg) translateZ(100px);
}
.flip .flip-card-side-b {
display:block;
transform: rotateY(0deg) translateZ(100px);
z-index: 1;
}
.flip-right .flip-card-side-a {
transform: rotateY(90deg) translateZ(100px);
}
.flip-
right .flip-card-side-b {
display:none;
}
.flip-right .flip-card-side-c {
transform: rotateY(0deg) translateZ(100px);
z-index:1;
}
JQUERY:
$("#button").on('click', function(){
$(".flip-card-content").removeClass("flip-right");
setTimeout(function(){
$(".flip-card-content").toggleClass("flip");
},500);
});
$("#button2").on('click', function(){
$(".flip-card-content").removeClass("flip");
setTimeout(function(){
$(".flip-card-content").toggleClass("flip-right");
},500);
});
Any advice is welcomed!
Your translateZ doesn't quite work in the way you expect. Have look at how I've positioned the faces on the cube here and compare it to your own. Ultimately, I find the easiest way to rotate items such as cubes etc. is to position all the elements and then just rotate the container.
Also for nice scaling of fonts, images etc. its preferable to leave the front face at its natural size rather than scale up (i.e. move everything backward in 3d space):
.box {
height: 100%;
position: relative;
transform: rotateX(0deg);
transform-origin: 50% 50% -100px;
transform-style: preserve-3d;
transition: all 1s;
width: 100%;
}
.box--rotate-top {
transform: rotateX(-90deg);
}
.box--rotate-left {
transform: rotateY(90deg);
}
.box__face {
backface-visibility: hidden;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.box__face--front {
background: #f90;
}
.box__face--top {
background: #369;
transform: rotateX(90deg) translateZ(200px);
transform-origin: 0 100% 0;
}
.box__face--left {
background: #867;
transform: rotateY(-90deg) translateZ(200px);
transform-origin: 100% 0 0;
}
Here is the fiddle.
Transition in 3d space are tricky, and different browsers can handle them differently.
Here you have your fiddle corrected.
Your best bet is to leave nothing to the browser imagination
so, instead of changing
transform: rotateY(0deg) translateZ(100px);
to
transform: rotateX(-90deg) translateZ(100px);
make the change happen from
transform: rotateX(0deg) rotateY(0deg) translateZ(100px);
to
transform: rotateX(-90deg) rotateY(0deg) translateZ(100px);
Notice that I didn't change the transform from a mathematical point of view; but now every property matches a similar one.
Note just in case you want to know, in the first case IE is making the followng transition: change the angle of rotation from 0 to -90deg. At the same time, change the axis of rotation from Y to X. So, at the middle of the transition, the rotation is wrong (from your point of view), but in a mathematic sense, both ways of understanding the transition make sense.