Safari 忽略关键帧动画的内联样式

Safari ignoring inline styles for keyframe animations

在 Safari(桌面和 iOS)中使用 CSS transform 设置 @keyframes 时只有一个结束帧,然后更新起始 transform以编程方式定位(通过 JS 内联),Safari 似乎继续从初始位置执行动画(即使用样式表中的初始转换值)——不使用内联样式。

简而言之,Safari 关键帧动画似乎不会更新以反映对以编程方式添加的内联样式的任何更改

下面的代码片段(简化的测试用例)在 Firefox 和 Chrome 中都有效,但 Safari 只是动画到 0 的位置。我的问题是是否有解决方法?这是 Apple 规范的预期表示吗,关键帧动画是否应该忽略编程内联样式?我无法想象他们应该这样做。

我试过克隆和替换元素,但无济于事。我还测试了包含 onLoad 的内联样式,这个 did 在 Safari 中工作,所以这个错误似乎只在添加样式时出现以编程方式。

我很感激我可以完全使用 JS 和 requestAnimationFrame 制作动画,如果上述方法失败,这是我的后备解决方案。 (同样,一个很好的解决方案是使用 Web Animation API,它似乎正是为此目的而设计的。但对它的支持是不完整的,所以现在不行)。我真正感兴趣的是上述错误的解决方案,而不是替代建议。

(顺便说一句,<marquee> 标签仍​​然可以用作跨浏览器解决方案... *shudder*)

// Get slides
let marquee = document.querySelector('.mock-marquee__content');

// Transform slides for initial offset
marquee.style.transform = `translate(-${marquee.clientWidth}px, 0)`;
.mock-marquee {
  overflow: hidden;
  display: flex;
}
.mock-marquee__content {
  white-space: nowrap;
  display: flex;
  animation: marquee 5s linear infinite;
}
.mock-marquee__content__slide {
  display: block;
}
.mock-marquee__content__slide:not(:first-child) {
  margin-left: 100px;
}
.mock-marquee__content:hover {
  animation-play-state: paused;
}

@keyframes marquee {
  from {
    transform: translate(100vw, 0);
  }
}
<div class="mock-marquee">
  <div class="mock-marquee__content">
    <span class="mock-marquee__content__slide">Hello</span>
    <span class="mock-marquee__content__slide">world</span>
    <span class="mock-marquee__content__slide">Foo</span>
    <span class="mock-marquee__content__slide">Bar</span>
    <span class="mock-marquee__content__slide">Bat</span>
    <span class="mock-marquee__content__slide">Another one</span>
    <span class="mock-marquee__content__slide">And another! Wowz</span>
  </div>
</div>

解决了!解决方案只是在 removing/adding 节点时强制排队,使用 setTimeout。像这样:

window.addEventListener('load', () => {
  let marqueeWrapper = marquee.parentNode;

  // Remove marquee
  marquee.remove();

  // Re-add, with forced queuing
  setTimeout(() => {
    marqueeWrapper.append(marquee);
  }, 0)
})

这会强制 Safari 完全重新渲染节点,似乎可以解决问题