Typically, when incorporating an animation
that alters the transform
property, it's important to ensure that the transforms specified in the base element are also included within the animation's keyframes. Essentially, the new transforms introduced by the animation should complement the existing transform
rather than completely replacing it. The correct approach is outlined below.
.loading {
position: relative;
width: 200px;
height: 200px;
background: #eee;
}
.loading:before,
.loading:after {
content: "";
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
transform: translate(100px, 300px);
animation: bounce 2s infinite ease-in-out;
}
.loading:after {
animation-delay: -1s;
}
@keyframes bounce {
0%, 100% {
transform: scale(0) translate(100px, 300px);
}
50% {
transform: scale(1) translate(100px, 300px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="loading"></div>
I provided a similar response here regarding applying multiple animations on an element where each animation independently affects the transform
property's values. I added this link for reference purposes and do not believe them to be duplicates.
In light of the above explanation, including the original transform in every animation's keyframes can be challenging when building animation libraries or separating animations into distinct classes. For instance, if you wish to apply the same bounce
animation to various elements with unique initial transform
settings, incorporating it directly into the animation's keyframe is unfeasible.
In such scenarios, accomplishing the desired outcome using CSS remains possible but significantly intricate (and almost impossible from my perspective) with one single element.
What alternatives exist? One option is to place the animation on a wrapping element.
.loading-wrapper {
position: relative;
width: 200px;
height: 200px;
background: #eee;
}
.loading-before, .loading-after {
position: absolute;
width: 50%;
height: 50%;
top: 0px;
left: 0px;
animation: bounce 2s infinite ease-in-out;
}
.loading-before:before,.loading-after:before {
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #fff;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
transform: translate(100px, 300px);
}
.loading-after {
animation-delay: -1s;
}
@keyframes bounce {
0%, 100% {
transform: scale(0);
}
50% {
transform: scale(1);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="loading-wrapper">
<div class="loading-before"></div>
<div class="loading-after"></div>
</div>
The solution presented is fairly versatile and applicable to a wide range of similar situations. However, a drawback is that stacking multiple transformations may necessitate numerous wrappers. There exists no pure CSS method other than integrating original transformations into the animation's keyframes.
Below is another demonstration snippet.
.move-n-scale {
position: relative;
height: 100px;
width: 100px;
background: sandybrown;
border: 1px solid chocolate;
transform: scale(0.5);
animation: move 1s linear infinite alternate-reverse;
}
.move {
position: relative;
display: inline-block;
animation: move-only 1s linear infinite alternate-reverse;
}
.scale {
position: absolute;
height: 100px;
width: 100px;
top: 0px;
left: 0px;
background: sandybrown;
border: 1px solid chocolate;
transform: scale(0.5);
}
@keyframes move {
from {
transform: translateX(0px) scale(0.5);
}
to {
transform: translateX(300px) scale(0.5);
}
}
@keyframes move-only {
from {
transform: translateX(0px);
}
to {
transform: translateX(300px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='move-n-scale'></div>
<div class='move'>
<div class='scale'></div>
</div>
Note: I acknowledge your preference against overly specific solutions like wrapping elements, but I included this answer as it represents the most generic solution available to me. The secondary snippet was shared purely to exemplify its generality.