笔记工具与开发

读取“减少动态效果”偏好:一个函数和一个 Hook

系统设置里的“减少动态效果”是读者明确表达过的偏好。动画开始之前先确认是否允许,并且在预渲染时给出确定的默认值。

本站允许读者在站内覆盖系统的动效偏好,所以判断分两步:站内有明确选择时以站内为准,否则跟随系统设置。

ts
export type MotionChoice = "system" | "full" | "reduced";

export function motionAllowed(choice: MotionChoice): boolean {
  if (choice !== "system") return choice === "full";
  return !matchMedia("(prefers-reduced-motion: reduce)").matches;
}

在 React 组件里,系统偏好可能在页面打开期间改变。用 useSyncExternalStore 订阅媒体查询,并为预渲染提供一个确定的快照:

tsx
import { useSyncExternalStore } from "react";

const QUERY = "(prefers-reduced-motion: reduce)";

function subscribe(onChange: () => void) {
  const mql = matchMedia(QUERY);
  mql.addEventListener("change", onChange);
  return () => mql.removeEventListener("change", onChange);
}

export function usePrefersReducedMotion(): boolean {
  return useSyncExternalStore(
    subscribe,
    () => matchMedia(QUERY).matches,
    () => false, // 预渲染与水合阶段使用固定值,水合后再读取真实偏好
  );
}

减少动效不等于取消反馈。按钮状态、焦点位置和加载提示仍然需要清楚可见,只是不再依赖位移和缩放来表达;淡入淡出这类不涉及运动的过渡通常可以保留。

参考:MDN · prefers-reduced-motion · React · useSyncExternalStore · WCAG 2.2 · Animation from Interactions

读到这里,
感谢你留下这一小段时间。

可访问性TypeScriptReact动效

发表评论…

公开讨论尚未连接

关于整篇文章,也关于让你停下来的那句话。
公开评论基于 GitHub Discussions;接入完成后才可发表。

正在加载评论…
发表评论
支持代码块与表情 · 评论公开可见0 / 6000

正在确认你的身份…

放大图片
搜索

输入关键词搜索标题、正文和标签。