Animation on SVG <use> does not work in FireFox & Safari

心不动则不痛 提交于 2021-01-28 01:58:01

问题


I have a transition animation I want to trigger on the width of an SVG element inside a group element. The animation only seems to work on the Chrome browser.

<!-- works -->
<svg width="400" height="100">
  <rect id="rect-1" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

<!-- only works in Chrome -->
<svg width="400" height="400">
  <defs>
    <g id="my-rect">
      <rect id="rect-2" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
    </g>
  </defs>

  <use xlink:href="#my-rect" y="0"/>
  <use xlink:href="#my-rect" y="110"/>
</svg>
.grow {
  -webkit-transition: 1.5s;
  -moz-transition: 1.5s;
  -o-transition: 1.5s;
  transition: 3s;
  width: 10px;
}
(() => {
  setTimeout(() => {
    const rect1 = document.getElementById('rect-1');
    rect1.classList.add('grow');

    const rect2 = document.getElementById('rect-2');
    rect2.classList.add('grow');
  }, 1000);
})();

To reproduce open this fiddle in Safari or Firefox. You will see that the transition of the second rectangle does not work properly.

Is there any workaround to get the transition animation working for a specific element inside the SVG group?


回答1:


use:

The element takes nodes from within the SVG document, and duplicates them somewhere else. - mdn

So It is unncesssery to use use since you do not duplicate it.

(() => {
  setTimeout(() => {
    const rect1 = document.getElementById('rect-1');
    rect1.classList.add('grow');

    const rect2 = document.getElementById('rect-2');
    rect2.classList.add('grow');

  }, 1000);
})();
.grow {
  -webkit-transition: 1.5s;
  -moz-transition: 1.5s;
  -o-transition: 1.5s;
  transition: width 3s;
  width: 10px;
}
<!-- works -->
<svg width="400" height="100">
  <rect id="rect-1" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

<svg width="400" height="100">
  <rect id="rect-2" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

Update 1

Even SVG <animate> does not work in FireFox when the element is duplicated. Though if not used inside the refrensed element. This is a known issue. There are multiple unanswered question on stackoverflow, for instance this one.

<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use -->

<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4" stroke="blue"/>
  <use href="#myCircle" x="10" fill="blue"/>
  <use href="#myCircle" x="20" fill="white" stroke="red"/>
  <!--
stroke="red" will be ignored here, as stroke was already set on myCircle. 
Most attributes (except for x, y, width, height and (xlink:)href)
do not override those set in the ancestor.
That's why the circles have different x positions, but the same stroke value.
  -->
  
      <animate 
           xlink:href="#myCircle"
           attributeName="r"
           from="4"
           to="2" 
           dur="5s"
           begin="0s"
           repeatCount="1"
           fill="freeze" 
           id="circ-anim"/>
           
           
</svg>

Update 2

Animations on a referenced element will cause the instances to also be animated. use - w3

Per documentation, if you animate the refrenced element (`myCircle), all the duplicate of it should be aniamted too. So I guess, it is a bug that it does not work in Firefox & Safari.

Update 3 - workaround

Use svg <animate> tag and enclose it in <rect>.

<svg width="400" height="400">
  <defs>
    <g id="my-rect">
      <rect id="rect-2" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)">
        <animate 
                 attributeName="width"
                 from="400"
                 to="10" 
                 dur="3s"
                 begin="1s"
                 repeatCount="1"
                 fill="freeze" 
                 id="rect-2"/>

      </rect>
    </g>
  </defs>

  <use xlink:href="#my-rect" y="0"/>
  <use xlink:href="#my-rect" y="110"/>
</svg>



回答2:


How about nesting the animate tag inside circle?

<svg width="400" height="350">
    <rect id="my-rect" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)">
        <animate 
               attributeName="width"
               from="0"
               to="400" 
               dur="5s"
               begin="0s"
               repeatCount="1"
               fill="freeze" 
               id="rect-anim"/>
    </rect>

    <use xlink:href="#my-rect" y="110"/>
    <use xlink:href="#my-rect" y="220"/>
     
</svg>



回答3:


Summarising, a workaround is to fall back to SMIL SVG animations instead of using CSS.

See the adapted fiddle to my original question.

<svg width="400" height="100">
  <rect id="rect-1" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

<svg width="400" height="400">
  <defs>
    <g id="my-rect">
      <rect id="g-rect" width="400" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)"/>
    </g>
  </defs>

  <use xlink:href="#my-rect" y="0"/>
  <use xlink:href="#my-rect" y="110"/>
</svg>
(() => {
  setTimeout(() => {
    const rect1 = document.getElementById('rect-1');
    rect1.classList.add('grow');

    const groupRect = document.getElementById('g-rect');

    const growAnimation = document.createElementNS('http://www.w3.org/2000/svg', 'animate')
    growAnimation.setAttribute('attributeName', 'width');
    growAnimation.setAttribute('from', '400');
    growAnimation.setAttribute('to', '10');
    growAnimation.setAttribute('dur', '3s');
    growAnimation.setAttribute('fill', 'freeze');
    growAnimation.setAttribute('begin', 'indefinite');
    groupRect.appendChild(growAnimation);

    growAnimation.beginElement();
  }, 1000);
})();


来源:https://stackoverflow.com/questions/60078402/animation-on-svg-use-does-not-work-in-firefox-safari

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!