配了八年 GIF,今天才发现 CSS 从来管不了它内部——Chrome 152 今天把这件事彻底原生化了

你有没有遇到过这种情况:页面上有个 GIF 动画,设计师说「这里要能暂停」,然后你翻了半天文档发现——对不起,没有标准 API,要么靠 JavaScript 操作 DOM 把图片 src 换成静态帧,要么直接告诉产品「浏览器不支持」。

这不只是你一个人的困境。WCAG 2.3.3 早就在要求「交互动画必须可关闭」,但 CSS 从来就没有一个正经属性来管图片动画。浏览器自动播放 GIF,开发者管不着,这个局面一直持续到了 Chrome 152。

Chrome 152(2026 年 8 月)正式把 image-animation 属性默认启用了。

这是 CSS 第一个真正管到 <img> 内部动画的标准属性。GIF、WebP 动画、APNG——全都在它的管辖范围内。

一行让整个页面安静下来

/* 暂停页面上所有图片动画 */
:root {
  image-animation: paused;
}

这就是最基础的用法。加上这一行,页面上所有 GIF、WebP 动画/APNG 全部停止在第一帧。不需要 JavaScript,不需要操作 DOM,CSS 直接告诉浏览器:「这些图片别播」。

有人会说:「那我直接用 CSS 把动画全关掉不就行了?」问题是 animation 属性只管 CSS @keyframes 动画,管不到 <img> 标签里的 GIF 动画。image-animation 是第一个能管到图片素材本身动画的属性。

有选择地暂停:装饰性动画停掉,功能性动画留着

无脑全局暂停有个问题:loading 指示器也是 GIF 或者 APNG,你把它停掉,用户就不知道页面还在加载了。

所以正确的用法是:先全局暂停,再把功能性动画单独放行。

/* 全局暂停 */
:root {
  image-animation: paused;
}

/* loading 指示器允许播放 */
.loading-indicator {
  image-animation: running;
}

有人会说:「那我直接用 CSS 把动画全关掉不就行了?」问题是 animation 属性只管 CSS @keyframes 动画,管不到 <img> 标签里的 GIF 动画。image-animation 是第一个能管到图片素材本身动画的属性。

:animated-image 伪类:自动识别动画图

但这里有个问题:怎么知道哪个图片是动画,哪个是静态图?靠类名太脆弱,你没法保证设计师上传的每个 loading 图都带类名。

:animated-image 伪类就是来解决这个问题的。

/* 只有动画图片的 loading-indicator 才放行 */
.loading-indicator:animated-image {
  image-animation: running;
}

:animated-image 表示「已加载的图片来源是动画格式」。如果是静态图,这个选择器根本不会匹配。相当于浏览器帮你做了一个格式检测,你只需要写选择器就行。

配合 prefers-reduced-motion:用户说关,就全关

image-animation 真正的价值在于和 prefers-reduced-motion 的配合。

/* 用户系统设置里勾了「减少动画」 */
@media (prefers-reduced-motion: reduce) {
  :root {
    image-animation: paused;
  }

  /* 功能性动画降级为只播一次,然后暂停 */
  .loading-indicator:animated-image {
    image-animation: once paused;
  }
}

once paused 是一个组合值:播放一轮动画,然后暂停。这对于 loading 指示器特别有用——用户不需要看无限循环的转圈,但他们需要知道「这里有东西在加载」。

controlled 值:把控制权还给用户

还有一个更激进的模式——controlled

/* 默认暂停,由用户提供播放触发 */
.decorative-gif {
  image-animation: controlled;
}

controlled 语义是:图片默认暂停,如果用户想看,浏览器会在图片上显示一个原生的播放按钮,用户点击后才开始播放。这和 <video controls> 的逻辑一致——浏览器自己提供 UI,不需要你写任何 JavaScript。

这个值对于营销类 GIF 特别有用。比如电商详情页里那些展示产品使用步骤的 GIF——它们是装饰性的,用户不一定要看,但有人想看的话可以点开。

为什么这件事 WCAG 早就在要求,但 CSS 一直没做

WCAG 2.3.3(AAA 级)要求:「由交互触发的动画,除非必要,否则必须可关闭。」但长期以来,CSS 能关闭的只有 CSS @keyframes 动画,GIF 动画完全不在 CSS 的管辖范围内。

这导致一个荒谬的局面:你可以用 CSS 让一个 <div> 的晃动动画停止,但没法让同一个页面上的一张 GIF 停止。只能用 JavaScript 换 src,或者靠浏览器扩展。

根本原因是:GIF 动画是图片格式本身的特性,CSS 历史上没有对应的概念。image-animation 是 CSS 第一次把图片格式的动画能力纳入标准控制范围。

浏览器支持现状

Chrome 152(2026 年 8 月)默认启用,Android 和 WebView 同版本跟进。Firefox 和 Safari 暂时没有明确信号。

由于目前只有 Chromium 系支持,渐进增强写法是:

/* 不支持的浏览器完全不处理,不影响原有行为 */
@supports (image-animation: paused) {
  @media (prefers-reduced-motion: reduce) {
    :root {
      image-animation: paused;
    }
  }
}

@supports 保证了这段代码只在浏览器支持时才生效,不支持的浏览器直接忽略,不会有任何副作用。

三个坑

第一个坑:image-animation 管的是图片格式的动画,不是 CSS 动画。 如果你页面上有个 CSS @keyframes 动画,这个属性管不到它。所以 prefers-reduced-motion 的完整实现通常需要两个配合:

@media (prefers-reduced-motion: reduce) {
  /* 关 CSS 动画 */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }

  /* 关图片动画 */
  :root {
    image-animation: paused;
  }
}

两者配合才能覆盖所有动画类型。

第二个坑:image-animation: running 不会让静态图动起来。 如果一张图本身就是静态的(PNG/JPEG),设置 running 不会有任何效果。这不是 bug,是设计逻辑:属性控制的是「播放状态」,不是「格式」。

第三个坑:prefers-reduced-motion 是用户设置,不是页面开关。 不要在你的 UI 里加一个「关闭动画」的按钮来替代系统设置——那只是在你的页面里模拟了系统设置的行为,但用户在其他网站遇到动画仍然没法关。正确的做法是:始终尊重 prefers-reduced-motion,不做自己的动画开关 UI。

现在可以用了吗

如果你面向的用户主要在 Chromium 浏览器(全球桌面浏览器 Chrome+Edge 合计占比很大),image-animation 加上 @supports 渐进增强可以安全上线。

对于 Safari/Firefox 用户,这段 CSS 会被忽略——GIF 仍然自动播放,这是 2026 年 9 月的现状。如果你需要完整覆盖,考虑在服务端对 GIF 做静态帧替换作为 fallback。

三步下一步:

  1. 先做审计:在 Chrome 里打开 DevTools,选中所有 <img> 标签,看 Network 面板里哪些请求的 MIME 类型是 image/gifimage/webp,这些就是你的动画图片
  2. 找 loading 指示器:把它们标记上 .loading-indicator 类,然后加 image-animation: running 例外
  3. @media (prefers-reduced-motion):把 image-animation: paused 写进你的全局 reduced-motion 媒体查询里,配合现有的 CSS 动画关闭规则一起用

GIF 动画从来不归 CSS 管——这个局面,Chrome 152 今天给关了。

评论区

0 条评论

登录后可评论。