Анимация по полукругу
Учусь перемещать div элементы вдоль кривой и для этого нашел хороший пример. Как перемещать между двумя кадрами разобрался, а с тремя сложнее. Не понимаю какой animation-timing-function нужно указать в @keyframes moveX на 50%. А то в одном случае анимация идет вдоль кривой с двумя изгибами, в другом - замечен рывок на кадре 50%.
Вот чего хочу добиться:
.contaiter {
position: relative;
width: 120px;
height: 200px;
border: 1px solid gray;
margin: 0 auto;
}
.x-axis, .y-axis {
animation-duration: 3s;
animation-fill-mode: both;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.x-axis {
position: absolute;
animation-name: moveX;
}
.y-axis {
animation-name: moveY;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: red;
}
@keyframes moveX {
0% {
transform: translateX(10px);
animation-timing-function: cubic-bezier(0.333333, 1, 0.666667, 1);
}
50% {
transform: translateX(100px);
}
100% {
transform: translateX(10px);
}
}
@keyframes moveY {
0% {
transform: translateY(190px);
animation-timing-function: cubic-bezier(0.333333, 0.305815, 0.666667, 0.806922);
}
100% {
transform: translateY(10px);
}
}
<div class="contaiter">
<div class="x-axis">
<div class="y-axis">
<div class="dot"></div>
</div>
</div>
</div>
Ответы (3 шт):
Максимально приближенное движение по полуокружности с помощью стандартных значений для animation-timing-function:
.contaiter {
margin: 0 auto;
height: 200px; width: 120px;
border: 1px solid gray;
background: radial-gradient(circle at 0% 50%, #fff8 98px, #000f 100px) no-repeat;
}
.x-axis, .y-axis {
display: inline-block;
animation: 6s ease-in-out alternate infinite;
}
.x-axis { animation-name: moveX; }
.y-axis { animation-name: moveY; }
.dot {
height: 10px; width: 10px;
border-radius: 50%;
background-color: red;
}
@keyframes moveX {
0% {
animation-timing-function: ease-out;
transform: translateX(0px);
}
50% {
animation-timing-function: ease-in;
transform: translateX(94px);
}
100% {
transform: translateX(0px);
}
}
@keyframes moveY {
0% { transform: translateY(190px); }
100% { transform: translateY(-10px); }
}
<div class="contaiter">
<div class="x-axis">
<div class="y-axis">
<div class="dot"></div>
</div>
</div>
</div>
Более точного и конкретного поведения можно добиться используя cubic-bezier().
Решение SVG
Мне всегда интересно смотреть, как задачи SVG решаются с помощью CSS.
В частности движение по криволинейной кривой. Хорошо, когда траектория движения это круг, а если это будет более сложная траектория, как во втором примере ниже?
Поверьте, я ни к чему особо не призываю, но наверное стоит присмотреться к SVG.
Многие графические задачи и анимации с помощью SVG решаются легче.
#1. Движение шарика вперед назад
Направление движение определяет пара атрибутов в animateMotion:
1.1 Вперед от начальной точки path
keyPoints="1;0"
keyTimes="0;1"
1.2 Назад к начальной точке path
keyPoints="0;1"
keyTimes="0;1"
1.3 Вперед - назад относительно начальной точки path
keyPoints="1;0;1"
keyTimes="0;0.5;1"
<div class="container" style="width:20vw;height:auto;">
<div><button onclick="forward.beginElement()">forward</button></div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 125 125" >
<path id="circ1" fill="none" stroke="black" stroke-dasharray="5 5" d="M60,20 A50,50 0 0, 1 60 120" />
<circle class="circ1" r="5" fill="red">
<animateMotion
id="forward"
dur="4s"
begin="indefinite"
repeatCount="indefinite"
keyPoints="0;1;0"
keyTimes="0;0.5;1"
calcMode="linear"
restart="whenNotActive">
<mpath xlink:href="#circ1"/>
</animateMotion>
</circle>
</svg>
</div>
#2. Движение шарика по синусоидальной траектории
Три кнопки управляют движением шарика вперед, с середины траектории, назад,
<button onclick="forward.beginElement()">forward</button>
<button onclick="middle.beginElement()">Middle</button>
<button onclick="back.beginElement()">Back</button>
<div>
<button onclick="forward.beginElement()">forward</button>
<button onclick="middle.beginElement()">Middle</button>
<button onclick="back.beginElement()">Back</button>
</div>
<div id="container">
<svg id="svg1" height="160" width="360">
<g transform="translate(0 -10)" stroke="black" stroke-width="1">
<path fill="none" stroke-dasharray="3" id="circ1"
d="M 10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" />
<circle class="circle2" r="8" fill="red">
<animateMotion
id="forward"
dur="2s"
begin="indefinite"
repeatCount="1"
keyPoints="0;1"
keyTimes="0;1"
calcMode="linear" >
<mpath href="#circ1" />
</animateMotion>
<animateMotion
id="middle"
dur="2s"
begin="indefinite"
repeatCount="1"
keyPoints="0.5;1"
keyTimes="0;1"
calcMode="linear" >
<mpath href="#circ1" />
</animateMotion>
<animateMotion
id="back"
dur="2s"
begin="indefinite"
repeatCount="1"
keyPoints="1;0"
keyTimes="0;1"
calcMode="linear" >
<mpath href="#circ1" />
</animateMotion>
</circle>
</g>
</svg>
Можно ещё вот так на CSS
Использована CSS функция @property
Работает только в Chromium движках (02 апреля 2021 года)
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #d1f3fa;
}
@property --x {
inherits: false;
initial-value: 0;
syntax: '<number>';
}
@property --y {
inherits: false;
initial-value: 0;
syntax: '<number>';
}
@property --rotate {
inherits: false;
initial-value: 0deg;
syntax: '<angle>';
}
.ball {
height: 10vmin;
width: 10vmin;
border-radius: 50%;
fill: #e69119;
background: #a16512;
animation: throw 2s infinite alternate ease-in-out;
transform: translateX(calc( var(--x) * 1vmin)) translateY(calc( var(--y) * 1vmin)) rotate(var(--rotate));
}
@keyframes throw {
0% {
--y: -40;
--rotate: 0deg;
}
50% {
--x: -30;
}
100% {
--y: 40;
--rotate: 360deg;
}
}
<svg class="ball" viewBox="0 0 496 512" title="basketball-ball">
<path d="M212.3 10.3c-43.8 6.3-86.2 24.1-122.2
53.8l77.4 77.4c27.8-35.8 43.3-81.2 44.8-131.2zM248
222L405.9 64.1c-42.4-35-93.6-53.5-145.5-56.1-1.2 63.9-21.5
122.3-58.7 167.7L248 222zM56.1 98.1c-29.7 36-47.5 78.4-53.8
122.2 50-1.5 95.5-17 131.2-44.8L56.1 98.1zm272.2 204.2c45.3-37.1
103.7-57.4 167.7-58.7-2.6-51.9-21.1-103.1-56.1-145.5L282
256l46.3 46.3zM248 290L90.1 447.9c42.4 34.9 93.6 53.5
145.5 56.1 1.3-64 21.6-122.4 58.7-167.7L248 290zm191.9
123.9c29.7-36 47.5-78.4 53.8-122.2-50.1 1.6-95.5 17.1-131.2
44.8l77.4 77.4zM167.7 209.7C122.3 246.9 63.9 267.3 0
268.4c2.6 51.9 21.1 103.1 56.1 145.5L214 256l-46.3-46.3zm116
292c43.8-6.3 86.2-24.1 122.2-53.8l-77.4-77.4c-27.7
35.7-43.2 81.2-44.8 131.2z" />
</svg>
