I’m quite not sure how to approach this.
I have a div that has its position controlled with using inline style from javascript, ie:
<div style="transform: translate3d(20px, 40px, 0);"></div>
I have a generic "shake" animation as follow
.shake{
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
backface-visibility: hidden;
perspective: 1000px;
transform-origin: center;
}
@keyframes shake {
10%, 90% {
transform: translateX(-2px);
}
20%, 80% {
transform: translateX(4px);
}
30%, 50%, 70% {
transform: translateX(-8px);
}
40%, 60% {
transform: translateX(8px);
}
}
If I apply my css class to the div, it will relocate the div to the top left of the screen. Is there a way to add to the existing translate3d from the animation, maybe with calc() ?
Ideally I’d like to do (pseudo code)
@keyframes shake {
10%, 90% {
transform: translateX(@current_translate_x - 2px);
}
....
>Solution :
There is now an animation-composition rule that you can set to tell how the properties set during the animation should affect the same properties already set before the animation:
.shake {
width: 30px;
height: 30px;
background: red;
}
:checked + .shake {
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
backface-visibility: hidden;
perspective: 1000px;
transform-origin: center;
animation-composition: add;
}
@keyframes shake {
10%, 90% {
transform: translateX(-2px);
}
20%, 80% {
transform: translateX(4px);
}
30%, 50%, 70% {
transform: translateX(-8px);
}
40%, 60% {
transform: translateX(8px);
}
}
<input type=checkbox>
<div class="shake" style="transform: translate3d(20px, 40px, 0);"></div>
If browser support is too low for you, then you can also achieve the same by using the translate property instead of transform: translate(), both will add up:
.shake {
width: 30px;
height: 30px;
background: red;
}
:checked + .shake {
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
backface-visibility: hidden;
perspective: 1000px;
transform-origin: center;
}
@keyframes shake {
10%, 90% {
transform: translateX(-2px);
}
20%, 80% {
transform: translateX(4px);
}
30%, 50%, 70% {
transform: translateX(-8px);
}
40%, 60% {
transform: translateX(8px);
}
}
<input type=checkbox>
<!-- Note how we now use the 'translate' property -->
<div class="shake" style="translate: 20px 40px;"></div>
If it’s still too edgy for you, you could still resort to the old good wrap in container and transform said container:
.shake-container > div {
width: 30px;
height: 30px;
background: red;
}
:checked + .shake-container > div {
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
backface-visibility: hidden;
perspective: 1000px;
transform-origin: center;
}
@keyframes shake {
10%, 90% {
transform: translateX(-2px);
}
20%, 80% {
transform: translateX(4px);
}
30%, 50%, 70% {
transform: translateX(-8px);
}
40%, 60% {
transform: translateX(8px);
}
}
<input type=checkbox>
<!-- we set the initial transform on the container -->
<div class="shake-container" style="transform: translate3d(20px, 40px, 0);">
<div></div>
</div>