Reputation: 4187
When using React to render a spinner in Chromium-based browsers, the transform-origin
property only updates after either of the following:
The spinner is built using styled-components
with the keyframes
helper, but since it works in Safari & Firefox, I'm not too sure it's a React issue after all.
Refer to the following GIF (apologies for the potato quality):
All other browsers produce the expected result immediately. Is this a known Chromium bug? Am I missing something here?
Edit:
Here's the Spinner element. It is the only thing being rendered from the App's entrypoint.
import React from "react";
import styled, { keyframes } from "styled-components";
import { COLOR_PRIMARY } from "core/constants";
const SpinnerWrapper = styled.div`
display: inline-block;
position: relative;
width: ${props => props.size || "2rem"};
height: ${props => props.size || "2rem"};
pointer-events: none;
`;
const spinnerAnimation = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
const SpinnerItem = styled.div`
box-sizing: border-box;
display: block;
position: absolute;
width: calc(100% - 12px);
height: calc(100% - 12px);
margin: 6px;
border: 2px solid #fff;
border-radius: 50%;
animation: ${spinnerAnimation} 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: ${props => props.inverse ? "white" : COLOR_PRIMARY} transparent transparent transparent;
animation-delay: ${props => props.delay || "0"}s;
transform-origin: 50% 50% !important;
`;
export default ({ size, inverse }) => (
<SpinnerWrapper size={size}>
<SpinnerItem inverse={inverse} delay={-.45} />
<SpinnerItem inverse={inverse} delay={-.3} />
<SpinnerItem inverse={inverse} delay={-.15} />
</SpinnerWrapper>
);
Upvotes: 1
Views: 249
Reputation: 3408
Without some example code demonstrating your problem, it is difficult to know if I am solving your actual issue or not, but I managed to get in a similar situation.
On this fiddle which approximately reproduces your animation, the transform-origin is changed to center when the mouse hovers the body, however on some browsers (can confirm current Chrome and Chromium 75) the value won't update while the animation is running unless, as you mentioned, the element gets inspected.
A possible trick that I have found is to reset the animation. You can do that by duplicating your keyframes declaration and switch to the alternate one when changing the transform origin:
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(1turn); }
}
@keyframes spin2 {
from { transform: rotate(0deg); }
to { transform: rotate(1turn); }
}
.part {
transform-origin: 0 0;
animation: spin 1.5s ease infinite;
}
body:hover .part {
transform-origin: center;
animation-name: spin2;
}
Here is a fiddle showing the trick.
If you don't want to duplicate your keyframes, I believe you could also use JS to remove the animation, force a reflow then add it again. Example:
// Removes the animation
myElement.style.animation = 'none';
// Forces a reflow - the browser will register that the animation was removed
myElement.clientWidth;
// Adds the animation back (resets it to what is defined in the CSS)
myElement.style.animation = '';
Upvotes: 1