配了八年 GIF,每次想暂停它都要写一堆 JS——今天 CSS 一个属性把这件事彻底原生化了

网页里 GIF 和 WebP 动图默认自动播放、无限循环,想让用户自己暂停?以前只能靠 JavaScript 监听交互再切换 src 或用 canvas 重绘。CSS Image Animation 模块给这件事写进了浏览器原生能力,一个属性搞定。

问题:动图控制一直是 JS 的活儿

CSS 能控制文字、盒子、动画帧,但管不了 GIF/WebP/APNG 自己怎么播。用户打开页面,动画自己跑;想让它停?要么浏览器全局设置,要么写一坨 JS 手动干预。这在无障碍场景下尤其尴尬——prefers-reduced-motion 用户希望能暂停页面上非必要的动效,但开发者根本没有标准手段。

方案:image-animation + :animated-image

CSS Image Animation Module Level 1 刚进 Chrome 154(其他浏览器还在跟进),给了两个新东西:

image-animation 控制播放行为,三个值:

/* 默认行为,动图正常播 */
img { image-animation: normal; }

/* 暂停在当前帧 */
img { image-animation: paused; }

/* 强制播放,不与其他实例同步 */
img { image-animation: running; }

:animated-image 伪类匹配实际加载了动图的 <img> 元素——只有当图片真的是动图时才生效,静态图不匹配。这让你可以精准地给「会动的图」加 UI,不用担心静态图也被套上样式。

一个真实场景的用法:

/* 全局:装饰性动图默认暂停 */
:root { image-animation: paused; }

/* 内容图保持正常播放 */
img.content { image-animation: normal; }

/* 给所有动图加一个浏览器原生的播放提示 */
img:animated-image::after {
  content: "▶";
  position: absolute;
  bottom: 4px;
  right: 4px;
  font-size: 10px;
  color: white;
  background: rgba(0,0,0,0.5);
  border-radius: 3px;
  padding: 2px 4px;
  pointer-events: none;
}

配合 prefers-reduced-motion 的正确姿势:

@media (prefers-reduced-motion: reduce) {
  :root { image-animation: paused; }
  /* 重要的 loading 动图保持播 */
  .loading-indicator { image-animation: normal; }
}

image-animation: running 还有一个细节:同 URL 的动图在同一元素内会同步播放,但切到 running 后会解除同步,每个实例独立走自己的时间线。这在做「同一动图多个实例各自播各自的」场景下很有用。

三个落地下一步

  1. 先做无障碍降级:把 image-animation: paused 写到全局根规则,配合 prefers-reduced-motion media query,先让有需求的用户不受干扰
  2. :animated-image 做 play/pause 切换:给动图包一层,hover 时切 running,离开切 paused,不用任何 JS 就能实现基础的交互控制
  3. 审计页面动图:跑一遍线上页面,找出哪些 GIF 是装饰性(可暂停)哪些是内容性(应保持播),分类套用不同策略

现在 Chrome 154+ 已稳定,Safari 也在路上。零 JS 成本地把动图控制权拿回来,这件事 CSS 今天自己会了。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 11 阅读