Как заставить совместно корректно работать анимации SVG и CSS?
Пытаюсь разобраться, как взаимодействуют анимации CSS и SVG. Для этого взял простейший сценарий:
- Персонаж перемещается справа налево с одновременными перемещениями вверх, вниз (svg)
- Поворот на 180 градусов (css) и
- движение назад слева-направо (css)
Вот код:
body { perspective: 1000px;}
.container{
width:80vw;
height:80vh;
}
#SnowMaiden {
transform-box:fill-box;
transform-origin: center center;
animation: Maiden_rotate 2s linear 8s forwards, Maiden_translate 14s linear 16s forwards;
}
@keyframes Maiden_rotate {
0%{ transform: rotate3d(0,1,0,20deg);}
50%{ transform: rotate3d(0,1,0,80deg);}
100%{ transform: rotate3d(0,1,0,180deg);}
}
@keyframes Maiden_translate {
0%{ transform: translate3d(300px,10px,10px);}
50%{ transform: translate3d(800px,10px,10px);}
100%{ transform: translate3d(1400px,10px,10px);}
}
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 1680 1050" preserveAspectRatio="xMinYMin meet" >
<!-- Фон с ёлочкой -->
<image id="img1" xlink:href="https://i.sstatic.net/PBRad.jpg" width="100%" height="100%" opacity="1" />
<image id="SnowMaiden" x="1400" y="650" xlink:href="https://i.sstatic.net/LU3Bvfdr.png" opacity="0">
<!-- Анимация появления девочки с корзинкой -->
<animate id="op1_Maidan" attributeName="opacity" values="0; 1" dur="2s" begin="svg1.click" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Перемещение по горизонтали -->
<animate id="Go_Maidan" attributeName="x" values="1400;1300;1200;1100;1000;900;800;700;600;500;400;300" dur="5s" begin="op1_Maidan.end" repeatCount="indefinity" fill="freeze" restart="whenNotActive" />
<!-- Перемещение по вертикали -->
<animate id="Go_Maidan_y" attributeName="y" values="650;670;650;630;650;670;650;630;650;670;650;630" dur="5s" begin="op1_Maidan.end" repeatCount="indefinity" fill="freeze" restart="whenNotActive" />
</image>
</svg>
Как видно из результата работы снипета:
Этап анимации SVG до поворота на 180 всё нормально.
Сбой начинается после поворота. Такое ощущение что CSS анимация вступила в конфликт с предыдущей анимацией SVG и поэтому не видно результата движения с помощью CSS.
Конечно можно реализовать анимации чисто на SVG или только с CSS.
И у меня вопрос, как заставить совместно корректно работать анимации SVG и CSS?
Ответы (2 шт):
тут дело не в SMIL
vs CSS
. просто выбранное свойство делает не совсем то что требуется.
body {perspective: 1000px}
#girl {
transform-box:fill-box;
transform-origin: center center;
animation:
mR 2s linear 9.5s forwards,
mT 5s linear 12s forwards,
mR 2s linear 17s reverse forwards;
}
@keyframes mR {
0% {transform: rotate3d(0,1,0,20deg)}
50% {transform: rotate3d(0,1,0,80deg)}
100% {transform: rotate3d(0,1,0,180deg)}
}
@keyframes mT {
/* transform: translate не меняет исходные координаты,
а смещает от них(300px+300px = 600px) */
0% {x: 300px; y: 630px}
10% {x: 410px; y: 650px}
20% {x: 520px; y: 670px}
30% {x: 630px; y: 650px}
40% {x: 740px; y: 630px}
50% {x: 850px; y: 650px}
60% {x: 960px; y: 670px}
70% {x: 1070px; y: 650px}
80% {x: 1180px; y: 630px}
90% {x: 1290px; y: 650px}
100%{x: 1400px; y: 670px}
}
<svg id="xyz" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1680 1050"
xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin meet" >
<image width="100%" height="100%" xlink:href="https://i.sstatic.net/PBRad.jpg"/>
<image id="girl" x="1400" y="650" opacity="0"
xlink:href="https://i.sstatic.net/LU3Bvfdr.png">
<animate id="spawn"
attributeName="opacity"
begin="xyz.click" values="0; 1"
dur="2s" repeatCount="1" fill="freeze" restart="whenNotActive" />
<animate
attributeName="x"
begin="spawn.end"
values="1400;1300;1200;1100;1000;900;800;700;600;500;400;300"
dur="5s" repeatCount="indefinity" fill="freeze" restart="whenNotActive"/>
<animate
attributeName="y"
begin="spawn.end"
values="650;670;650;630;650;670;650;630;650;670;650;630"
dur="5s" repeatCount="indefinity" fill="freeze" restart="whenNotActive"/>
</image>
</svg>
Решение SVG
Добавлено зацикливание пакета анимаций: движения + поворота.
Зацикливание достигается условием:
begin="op1_Maidan.end;scale_M2.end"
, где
scale_M2.end"
- окончание анимации поворота персонажа в начальной точке после первого цикла.
.container{
width:80vw;
height:80vh;
}
#SnowMaiden {
transform-box:fill-box;
transform-origin: center center;
}
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 1680 1050" preserveAspectRatio="xMinYMin meet" >
<!-- Фон с ёлочкой -->
<image id="img1" xlink:href="https://i.sstatic.net/PBRad.jpg" width="100%" height="100%" opacity="1" />
<image id="SnowMaiden" x="1400" y="650" xlink:href="https://i.sstatic.net/LU3Bvfdr.png" opacity="0">
<!-- Анимация появления девочки с корзинкой -->
<animate id="op1_Maidan" attributeName="opacity" values="0; 1" dur="2s" begin="svg1.click" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Перемещение по горизонтали -->
<animate id="Go_Maidan" attributeName="x" values="1400;1300;1200;1100;1000;900;800;700;600;500;400;300" dur="5s" begin="op1_Maidan.end;scale_M2.end" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Перемещение по вертикали -->
<animate id="Go_Maidan_y" attributeName="y" values="650;670;650;630;650;670;650;630;650;670;650;630" dur="5s" begin="Go_Maidan.begin" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Поворот -->
<animateTransform id="scale_M" attributeName="transform" type="scale" values="-1 1" begin="Go_Maidan_y.end" dur="0.1s" fill="freeze" />
<!-- Назад по Х -->
<animate id="Go_back_x" attributeName="x" values="300;400;500;600;700;800;900;1000;1100;1200;1300;1400" dur="5s" begin="scale_M.end" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Назад по Y -->
<animate id="Go_back_y" attributeName="y" values="650;670;650;630;650;670;650;630;650;670;650;630" dur="5s" begin="scale_M.end" repeatCount="1" fill="freeze" restart="whenNotActive" />
<!-- Поворот -->
<animateTransform id="scale_M2" attributeName="transform" type="scale" values="1 1" begin="Go_back_y.end" dur="0.1s" fill="freeze" />
</image>
</svg>