Safari中图像元素的CSS动画效果与预期不符

4

以下是我在Safari中遇到的一个最小化的错误样本。


期望行为:代码应该在另一张图片加载时显示占位符,然后淡入该图像并删除占位符。

placeholder -> fading in loaded image

实际表现: 在Chrome和Mozilla中按预期工作,但在Safari中失败,导致以下效果:

placeholder -> white screen -> loaded image

请问有人能帮我解决为什么在Safari中会出现这种情况吗?(尝试在Chrome或Mozilla与Safari中运行下面的示例以查看结果。)

const image = new Image();

image.onload = () => {
  document.getElementById('placeholder').remove();

  const el = document.createElement('img');
  el.setAttribute('src', 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
  el.setAttribute('width', '150');
  el.setAttribute('height', '150');

  el.style = `
    animation-name: testAnimation;
    animation-duration: 0.3s;
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    background: red;
  `;

  document.body.appendChild(el);
}

image.src = 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
  background: #eee;
}

@-webkit-keyframes testAnimation {
  0% {
    opacity: 0.25;
  }
  50% {
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">

(

还有一个奇怪的行为是,如果将animation-duration增加到大约3-4秒,那么图像确实会淡入,但是白色屏幕仍然存在,也就是说:

placeholder -> white screen -> fading in loaded image

)

更新:

在尝试调整img的背景颜色后,似乎在Safari浏览器中,动画效果开始生效的时间比图片渲染到屏幕上早了约1秒。

  • 因此,如果真实图片没有像占位符图片一样的背景颜色,则会出现白色闪烁,因此在为真实图片添加背景颜色后,该背景颜色会在图片开始显示之前约1秒钟变得可见
  • 因此,淡入淡出效果也会在图片开始显示之前约1秒钟开始发生

而在Chrome和Mozilla浏览器中,动画似乎与图片完全同步。

运行更新的代码以自己查看

(它似乎只发生在<img>中,我已经测试过其他一些元素(仍在image.onload内)并且它们按预期工作。)

更新2:请参见下面的答案修复和说明

2个回答

3
通过在图像元素而不是显式的Image对象上添加另一个onload事件并将image.onload侦听器放入其中来解决了这个问题。
这似乎表明,在Safari中,动画和样式是在将<img>添加到DOM之前应用的 - 在完全加载它(调用其onload事件)之前。
  • 可以通过给<img>设置背景颜色并查看它随动画一起显示,以测试此功能,因为该元素添加到DOM后立即出现,而且需要额外的一秒钟才能看到图像本身变得可见。

  • 也可以通过仅给<img>设置背景颜色而不使用任何动画来看到相同的效果。

(Safari中的一个错误? 我的Safari版本:版本11.0.2(13604.4.7.1.3)) 编辑:实际上,问题似乎是由缓存引起的,Safari似乎没有缓存预加载的代理图像,而其他浏览器确实会缓存它。当它呈现到屏幕上时,Safari似乎会为该图像发出另一个请求 - 因此在看到实际图像之前可以看到样式,因为图像仍在下载。 编辑2:经过进一步调查,似乎Safari实际上是这3个浏览器中唯一表现正常的浏览器 - 这是因为图像的HTTP响应包含一个Cache-Control: no-cache, must-revalidate头,明确指示浏览器不要缓存图像。

const image = new Image();
    
const el = document.createElement('img');
el.setAttribute('src', 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
el.setAttribute('width', '150');
el.setAttribute('height', '150');
el.style = `
  animation-name: testAnimation;
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  background-color: red;
`;
    
el.onload = () => {
  image.onload = () => {
    document.getElementById('placeholder').remove();
    document.body.appendChild(el);
  }
}

image.src = 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
  background: #eee;
}

@-webkit-keyframes testAnimation {
  0% {
    opacity: 0.25;
  }
  50% {
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">


1
这似乎与您使用的特定服务器/图像有关。我尝试仅更改图像URL(为wikimedia.org上的某些内容,仅用于测试目的),在Safari 11.0.2(13604.4.7.1.6)中,动画开始按预期工作。
预加载图片可能会有所帮助...或者更好的方法(前提是您拥有适当的使用权,当然),您可以尝试将图像复制到Web服务器上,以便可以本地加载。实质上,您只是纠正了Safari完成运行动画的事实,因为它可以从远程服务器加载图像。您还可以尝试使用window.onload而不是image.onload,以强制在运行之前加载所有外部资源。

它在Chrome和Mozilla上可以工作,但仍然无法在Safari上工作。 - linasmnew
我目前在Safari中运行该fiddle,并且它似乎正常工作。也许您正在使用较旧版本的Safari?我在High Sierra 10.13.2上运行11.0.2(13604.4.7.1.6)。 - Criminally Inane
我的Safari版本:版本11.0.2(13604.4.7.1.3),操作系统版本:10.13.2。 - linasmnew
所以在显示图像之前不需要等待网络请求,只有在成功下载图像后才创建和显示图像元素 - 在其他浏览器中这很好用,只有Safari需要另一个onload事件,这次是在图像元素上而不是在Image对象上。 - linasmnew
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Criminally Inane
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接