Анимация на SVG <use>не работает в FireFox и Safari - PullRequest
2 голосов
/ 05 февраля 2020

У меня есть анимация перехода, которую я хочу запустить по ширине элемента SVG внутри элемента группы. Кажется, что анимация работает только в браузере Chrome.

<!-- 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);
})();

Для воспроизведения откройте эту скрипку в Safari или Firefox. Вы увидите, что переход второго прямоугольника не работает должным образом.

Есть ли обходной путь, чтобы анимация перехода работала для определенного элемента c внутри группы SVG?

Ответы [ 3 ]

2 голосов
/ 05 февраля 2020

use:

Элемент берет узлы из документа SVG и дублирует их где-то еще. - mdn

Так что использовать use бесполезно, поскольку вы не дублируете его.

(() => {
  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>

Обновление 1

Даже SVG <animate> не работает в FireFox, когда элемент дублируется. Хотя, если не используется внутри обновленного элемента. Это известная проблема. Есть много вопросов без ответа о стеке потока, например этот .

<!-- 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>

Обновление 2

Анимации на элементе, на который есть ссылка, также приводят к анимации экземпляров. use - w3

Согласно документации, если вы анимируете связанный элемент (`myCircle), все его дубликаты также должны быть анимированы. Так что я думаю, это ошибка, что она не работает в Firefox & Safari.

Обновление 3 - обходной путь

Используйте тег svg <animate> и заключите его в <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>
1 голос
/ 06 февраля 2020

Как насчет вложения тега animate в круг?

<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>
0 голосов
/ 06 февраля 2020

Подводя итог, обходной путь заключается в использовании SMIL SVG-анимаций вместо использования CSS.

См. Адаптированный fiddle к моему первоначальному вопросу.

<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);
})();
...