问题描述
正如标题所述,我正在尝试在看起来像省略号路径的svg上进行动画处理 第一个图标(无穷大符号)。我试过使用转换,但是动作很糟糕。我该如何以一种流畅的方式实现这一目标?
我找到了一些有关类似内容的文章,但并没有使我得到平滑的省略号: https://www.useragentman.com/blog/2013/03/03/animating-circular-paths-using-css3-transitions/ http://thenewcode.com/860/Animating-Elements-In-Arcs-Circles-and-Ellipses-With-CSS https://usefulangle.com/post/32/moving-an-element-in-circular-path-with-css
这是笔https://codepen.io/acubaniti/pen/abNqzEV?editors=1100的链接
这是代码:
#gesture {
width: 300px;
height: 300px;
}
#phone {
fill: white;
animation: phone-orbits-cw 6s cubic-bezier(0.5,0.38,0.1) infinite;
opacity: 0;
transform: rotate3d(0,0) translate3d(0,0);
will-change: transform,opacity;
transform-style: preserve-3d;
transform-origin: center top;
}
#left,#right {
fill: none;
stroke-width: 10;
stroke-miterlimit: 10;
stroke: white;
transform-origin: 200px 150px;
animation-fill-mode: forwards;
stroke-dasharray: 314;
stroke-dashoffset: 314;
opacity: 0;
}
#right {
animation: circle-fill 6s linear infinite;
stroke: white;
transform: rotate(-180deg);
}
#left {
animation: circle-fill-left 6s linear infinite;
stroke: white;
transform: rotateX(180deg);
}
@keyframes circle-fill {
0%,12.5% {
stroke-dashoffset: 314;
opacity: 1;
}
12.5%,100% {
stroke-dashoffset: 0;
}
37.5% {
opacity: 1;
}
49%,100% {
opacity: 0;
}
}
@keyframes circle-fill-left {
12.5% {
stroke-dashoffset: 314;
opacity: 1;
}
25% {
stroke-dashoffset: 0;
}
37.5% {
opacity: 1;
}
49%,100% {
opacity: 0;
stroke-dashoffset: 0;
}
}
@keyframes phone-orbits-cw {
0% {
opacity: 0;
transform: rotate3d(0,0);
}
45% {
opacity: 0;
transform: rotate3d(0,1,-360deg) translate3d(2%,-5%,0) rotate3d(0,360deg);
}
58.75% {
opacity: 1;
transform: rotate3d(0,360deg);
}
72.5% {
opacity: 1;
}
86.25% {
opacity: 1;
transform: rotate3d(0,360deg) translate3d(-2%,-360deg);
}
100% {
opacity: 1;
transform: rotate3d(0,-360deg) translate3d(0,360deg);
}
}
@keyframes phone-orbits-ccw {
0% {
opacity: 0;
transform: rotate3d(0,0);
}
40% {
opacity: 0;
transform: rotate3d(0,180deg) translate3d(0,-180deg);
}
45% {
opacity: 1;
}
50% {
opacity: 1;
transform: rotate3d(0,-180deg) translate3d(2%,180deg);
}
75% {
opacity: 1;
}
100% {
opacity: 1;
transform: rotate3d(0,-180deg);
}
}
<html>
<body style="background-color: black;">
<svg id="gesture" viewBox="0 0 300 300" xml:space="preserve">
<g id="phone">
<path d="M212.1 23.1H90.2c-4.8 0-8.8 3.9-8.8 8.8v236.4c0 4.8 3.9 8.8 8.8 8.8h121.9c4.8 0 8.8-3.9 8.8-8.8V31.8c0-4.8-4-8.7-8.8-8.7zm0 8.5c.1 0 .2.1.2.2v28.4H90.2V31.6h121.9zM90 268.2l.2-200.6h122.1l-.2 200.8-122.1-.2z"/>
<circle cx="151.1" cy="248.2" r="8.8"/>
<path d="M142 49.5h18.3c2.3 0 4.1-1.8 4.1-4.1s-1.8-4.1-4.1-4.1H142c-2.3 0-4.1 1.8-4.1 4.1s1.8 4.1 4.1 4.1z"/>
</g>
<circle id="right" cx="200" cy="150" r="50"/>
<circle id="left" cx="100" cy="150" r="50"/>
</svg>
</body>
</html>
谢谢。
解决方法
如果您可以牺牲浏览器的兼容性,则应该可以使用motion path以更加语义化的方式来做到这一点。它需要Chrome 64,Edge 79,Firefox 72,Opera 45,但不支持Safari。
以下示例以多种方式简化了代码。首先,我将两个圆重写为一条路径,并对其进行了另外的移动,以使路径的起点和终点(“无穷大”符号的中点)位于坐标系的原点。这是因为此路径将被重用为运动路径-不用引号,如果您使用CSS,这是不可能的,但是您只需复制并粘贴路径命令即可。
通过stroke-dashoffset
动画使我的生活更轻松,该路径还获得了属性(不是CSS属性!)pathLength="100"
。这基本上是一个任意值,这意味着:对于所有沿路径的距离计算,将视为 100作为路径长度。
第二,我使用相同的路径命令定义了一个offset-path
。将offset-rotate
设置为0deg
以避免手机在移动时沿切线路径旋转。在动画过程中,offset-distance
从0增加到100%。
#gesture {
width: 300px;
height: 300px;
}
#phone {
fill: white;
animation: phone-orbit 6s ease-in-out infinite;
opacity: 0;
offset-path: path("M0 0 A 30 30 0 0 1 60 0 A 30 30 0 0 1 0 0 A 30 30 0 0 0 -60 0 A 30 30 0 0 0 0 0");
offset-rotate: 0deg;
offset-distance: 0;
will-change: transform,opacity;
}
#infinity {
fill: none;
stroke-width: 6.666;
stroke: white;
animation-fill-mode: forwards;
stroke-dasharray: 100;
stroke-dashoffset: 100;
opacity: 0;
animation: infinity-fill 6s linear infinite;
}
@keyframes infinity-fill {
0%,25% {
stroke-dashoffset: 100;
opacity: 1;
}
25%,100% {
stroke-dashoffset: 0;
}
37.5% {
opacity: 1;
}
49%,100% {
opacity: 0;
}
}
@keyframes phone-orbit {
0% {
opacity: 0;
}
40% {
opacity: 0;
}
45% {
opacity: 1;
}
50% {
offset-distance: 0%;
}
100% {
opacity: 1;
offset-distance: 100%;
}
}
<body style="background-color: black;">
<svg id="gesture" viewBox="0 0 300 300" xml:space="preserve">
<g id="phone">
<path d="M212.1 23.1H90.2c-4.8 0-8.8 3.9-8.8 8.8v236.4c0 4.8 3.9 8.8 8.8 8.8h121.9c4.8 0 8.8-3.9 8.8-8.8V31.8c0-4.8-4-8.7-8.8-8.7zm0 8.5c.1 0 .2.1.2.2v28.4H90.2V31.6h121.9zM90 268.2l.2-200.6h122.1l-.2 200.8-122.1-.2z"/>
<circle cx="151.1" cy="248.2" r="8.8"/>
<path d="M142 49.5h18.3c2.3 0 4.1-1.8 4.1-4.1s-1.8-4.1-4.1-4.1H142c-2.3 0-4.1 1.8-4.1 4.1s1.8 4.1 4.1 4.1z"/>
</g>
<path id="infinity" transform="translate(150 150) scale(1.666)" d="M0 0 A 30 30 0 0 1 60 0 A 30 30 0 0 1 0 0 A 30 30 0 0 0 -60 0 A 30 30 0 0 0 0 0" pathLength="100"/>
</svg>
</body>
要获得更好的支持,您可以切换到标记内SMIL animation。只有旧版本的IE才能使您失望。
差异主要在于不同动画的启动方式:除了第一个infinityFill
动画从0s开始之外,每个后续动画均根据其运行时开始。尤其是phoneOrbit
动画从infinityFill
动画的结尾开始,然后phoneOrbit
的结尾再次从infinityFill
开始,依此类推,直到无穷大。
另外,运动路径可以真正地重用。
#gesture {
width: 300px;
height: 300px;
}
#phone {
fill: white;
opacity: 0;
will-change: transform,opacity;
}
#infinity {
fill: none;
stroke-width: 10;
stroke: white;
stroke-dasharray: 100;
opacity: 0;
}
<body style="background-color: black;">
<svg id="gesture" viewBox="0 0 300 300">
<defs>
<path id="motion" d="M0 0 A 30 30 0 0 1 60 0 A 30 30 0 0 1 0 0 A 30 30 0 0 0 -60 0 A 30 30 0 0 0 0 0" pathLength="100"/>
</defs>
<g id="phone">
<path d="M212.1 23.1H90.2c-4.8 0-8.8 3.9-8.8 8.8v236.4c0 4.8 3.9 8.8 8.8 8.8h121.9c4.8 0 8.8-3.9 8.8-8.8V31.8c0-4.8-4-8.7-8.8-8.7zm0 8.5c.1 0 .2.1.2.2v28.4H90.2V31.6h121.9zM90 268.2l.2-200.6h122.1l-.2 200.8-122.1-.2z"/>
<circle cx="151.1" cy="248.2" r="8.8"/>
<path d="M142 49.5h18.3c2.3 0 4.1-1.8 4.1-4.1s-1.8-4.1-4.1-4.1H142c-2.3 0-4.1 1.8-4.1 4.1s1.8 4.1 4.1 4.1z"/>
<animateMotion id="phoneOrbit" dur="3s"
begin="infinityFill.end" rotate="0">
<mpath href="#motion" />
</animateMotion>
<animate attributeName="opacity" dur="6s"
begin="infinityFill.begin"
values="0;0;1;1" keyTimes="0;.45;.5;1" />
</g>
<use id="infinity" href="#motion" transform="translate(150 150) scale(1.666)">
<animate id="infinityFill" attributeName="stroke-dashoffset"
dur="3s" begin="0s;phoneOrbit.end"
values="100;0;0" keyTimes="0;.5;1" />
<animate attributeName="opacity" dur="3s"
begin="infinityFill.begin"
values="1;1;0" keyTimes="0;.75;1" />
</use>
</svg>
</body>