IMG 标签中的动画 SVG 精灵在水平方向振动

Animated SVG sprite in IMG tag vibrates in horizontal direction

查看 24 个精灵帧中弹跳圆的代码片段。

<text y='12'>n:0</text> 显示 sprite framenr

如何摆脱水平抖动移动,是SVG还是CSS?

精灵帧数越少偏移量越小,每个精灵帧数越多偏移量越差

在 Chromium 中不太明显,在 FireFox 中更明显

我试过了https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio

<style>
  #bounce {
    --w: 200px;
    width: var(--w);
    height: var(--w);
    overflow: hidden;
    display: inline-flex;
    background: lightgreen;
  }

  img {
    position: relative;
    left: 0;
    animation: moveX 1s steps(23) infinite;
  }

  @keyframes moveX {
    to {
      transform: translate(-100%);
      left: 100%;
    }
  }

</style>
<div id="bounce"><img id=svgimg src="SVG injected here"></div>
<script>
  window.onload = () => svgimg.src = `data:image/svg+xml,` + svg.innerHTML;
</script>
<template id=svg>
  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2400 100' height='200'>
    <style>
      ellipse {
        fill: none;
        stroke: green;
        stroke-width: 5;
      }

    </style>
    <g transform='translate(0 0)'>
      <ellipse cx='50' cy='32' rx='30' ry='30'></ellipse><text y='12'>n:0</text>
    </g>
    <g transform='translate(100 0)'>
      <ellipse cx='50' cy='32.3' rx='30' ry='30'></ellipse><text y='12'>n:1</text>
    </g>
    <g transform='translate(200 0)'>
      <ellipse cx='50' cy='33.2' rx='30' ry='30'></ellipse><text y='12'>n:2</text>
    </g>
    <g transform='translate(300 0)'>
      <ellipse cx='50' cy='34.5' rx='30' ry='30'></ellipse><text y='12'>n:3</text>
    </g>
    <g transform='translate(400 0)'>
      <ellipse cx='50' cy='36.5' rx='30' ry='30'></ellipse><text y='12'>n:4</text>
    </g>
    <g transform='translate(500 0)'>
      <ellipse cx='50' cy='39' rx='30' ry='30'></ellipse><text y='12'>n:5</text>
    </g>
    <g transform='translate(600 0)'>
      <ellipse cx='50' cy='42' rx='30' ry='30'></ellipse><text y='12'>n:6</text>
    </g>
    <g transform='translate(700 0)'>
      <ellipse cx='50' cy='45.7' rx='30' ry='30'></ellipse><text y='12'>n:7</text>
    </g>
    <g transform='translate(800 0)'>
      <ellipse cx='50' cy='49.8' rx='30' ry='30'></ellipse><text y='12'>n:8</text>
    </g>
    <g transform='translate(900 0)'>
      <ellipse cx='50' cy='54.5' rx='31.3' ry='30'></ellipse><text y='12'>n:9</text>
    </g>
    <g transform='translate(1000 0)'>
      <ellipse cx='50' cy='59.8' rx='33.9' ry='30'></ellipse><text y='12'>n:10</text>
    </g>
    <g transform='translate(1100 0)'>
      <ellipse cx='50' cy='65.7' rx='36.9' ry='30'></ellipse><text y='12'>n:11</text>
    </g>
    <g transform='translate(1200 0)'>
      <ellipse cx='50' cy='72' rx='40' ry='30'></ellipse><text y='12'>n:12</text>
    </g>
    <g transform='translate(1300 0)'>
      <ellipse cx='50' cy='65.7' rx='36.9' ry='30'></ellipse><text y='12'>n:13</text>
    </g>
    <g transform='translate(1400 0)'>
      <ellipse cx='50' cy='59.8' rx='33.9' ry='30'></ellipse><text y='12'>n:14</text>
    </g>
    <g transform='translate(1500 0)'>
      <ellipse cx='50' cy='54.5' rx='31.3' ry='30'></ellipse><text y='12'>n:15</text>
    </g>
    <g transform='translate(1600 0)'>
      <ellipse cx='50' cy='49.8' rx='30' ry='30'></ellipse><text y='12'>n:16</text>
    </g>
    <g transform='translate(1700 0)'>
      <ellipse cx='50' cy='45.7' rx='30' ry='30'></ellipse><text y='12'>n:17</text>
    </g>
    <g transform='translate(1800 0)'>
      <ellipse cx='50' cy='42' rx='30' ry='30'></ellipse><text y='12'>n:18</text>
    </g>
    <g transform='translate(1900 0)'>
      <ellipse cx='50' cy='39' rx='30' ry='30'></ellipse><text y='12'>n:19</text>
    </g>
    <g transform='translate(2000 0)'>
      <ellipse cx='50' cy='36.5' rx='30' ry='30'></ellipse><text y='12'>n:20</text>
    </g>
    <g transform='translate(2100 0)'>
      <ellipse cx='50' cy='34.5' rx='30' ry='30'></ellipse><text y='12'>n:21</text>
    </g>
    <g transform='translate(2200 0)'>
      <ellipse cx='50' cy='33.2' rx='30' ry='30'></ellipse><text y='12'>n:22</text>
    </g>
    <g transform='translate(2300 0)'>
      <ellipse cx='50' cy='32.3' rx='30' ry='30'></ellipse><text y='12'>n:23</text>
    </g>
  </svg></template>

备注

我可以使用库,我正在生成(和更改)精灵表客户端

此圈子的模板是 模板文字:

<template id="bounce">
  <ellipse cx='50' 
           cy='${72-1*ease(40)}' 
           rx='${minmax(30,40-ease(20))}' 
           ry='30' fill='none' stroke='black' stroke-width='5'>
  </ellipse>
  <text y='12'>n:${framenr}</text>
</template>

Web 组件然后(重新)创建 sprite 和 IMG,以及显示 sprite 的所有内容

<svg-spriter do="bounce" steps="24" duration="1s" animation="infinite"></svg-spriter>

我对 fiddle 进行了一些更改,它似乎有效。有一点似乎是,变换中最后一个left坐标应该是svg的总长度减去window的长度。在fiddle中,您可以更改

transform: translate(calc(-1 * var(--steps) * var(--w)));

transform: translate(calc(-1 * calc(var(--steps) - 1) * var(--w)));

在您的代码段中,transform: translate(-100%); 百分比应为 (2300/2400)*100

更重要的是,我在 svg 中添加了 width='2400' 属性。为 svg 设置缺失长度 属性 的问题相当复杂,我认为每个浏览器的行为方式都不相同。

在fiddle中,我把--w属性改成了100,也就是每个svg帧的高和宽。如果要设置为200,则需要按比例更改svg的大小和每帧的坐标。

是的,这似乎与您的框架对齐方式有关。如果我在没有平移的情况下绘制所有省略号并且不透明度为 0.05,它会给出此图像:

虽然粗体绿色的厚度在左侧不知何故少了一个像素,但乍一看还可以。因此,在其“空气”位置尝试使用奇数宽度的椭圆可能是值得的。

BTW SVG(规范)也有您可能会使用的 shape-rendering 参数,但在您的情况下这应该很少成为问题:

SVG shape-rendering