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

Posted

技术标签:

【中文标题】Safari 忽略关键帧动画的内联样式【英文标题】:Safari ignoring inline styles for keyframe animations 【发布时间】:2020-07-29 16:41:47 【问题描述】:

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

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

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

我尝试克隆和替换元素,但无济于事。我还测试了包含 onLoad 的内联样式,并且这个 确实 在 Safari 中工作,因此该错误似乎仅在以编程方式添加样式时出现。

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

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

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

// Transform slides for initial offset
marquee.style.transform = `translate(-$marquee.clientWidthpx, 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>

【问题讨论】:

【参考方案1】:

解决了!解决方案只是在删除/添加节点时使用setTimeout 强制队列。像这样:

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

  // Remove marquee
  marquee.remove();

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

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

【讨论】:

我遇到了类似的问题,我解决的方法是通过js使用CSSOM(CSS对象模型)更改关键帧名称,然后更新元素上的animationName。你的是一个更清洁的解决方案。这让我相信在 Safari 中,当动画应用于元素时,它会被缓存,但不会监听任何更新,即使通过 CSSOM。

以上是关于Safari 忽略关键帧动画的内联样式的主要内容,如果未能解决你的问题,请参考以下文章

多个关键帧动画在 Safari 中不起作用

CSS关键帧动画在Safari中不起作用

Safari上的flexbox动画关键帧

关键帧中的非动画属性在 iOS 上被忽略

无法使用带有样式组件的关键帧设置嵌套动画的样式

Css3之高级-7 Css动画(概述关键帧动画属性)