mcpField
U
user-personalization

user-personalization

github.com/mgifford设计与 UI57138 次安装6 周前更新
代码仓库

关于 user-personalization

面向实现或审查个性化设置的无障碍指南,适用于含主题、字号等偏好功能的项目。重点是让站点设置尊重系统偏好,并与 WCAG 基础要求区分。

主要功能

  1. 01遵循系统与浏览器偏好
  2. 02设计可访问的设置控件
  3. 03安全验证并保存偏好
  4. 04减少动效且保留信息
  5. 05检查主题与预设的无障碍性

适用场景

  1. 01审查主题和字号设置
  2. 02实现尊重系统设置的动效选项
  3. 03检查偏好数据的存储与重置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mgifford/accessibility-skills --skill user-personalization

安装后在 Claude Code 中输入/user-personalization确认已加载。

附带文件SYNC.md

详细介绍

用户个性化无障碍技能

规范来源:mgifford/ACCESSIBILITY.md 中的 examples/USER_PERSONALIZATION_ACCESSIBILITY_BEST_PRACTICES.md 此技能源自该文件。如有疑问,以示例为准。

实施用户偏好设置控件或评审现有个性化功能时,请遵循以下规则。 仅当项目具有个性化功能时,才加载此技能。


核心要求

个性化是在无障碍基础上的增强,而非修补层,也不能替代 WCAG 合规性。首先尊重操作系统、浏览器和辅助技术(AT)的设置;只有当网站专属控件能提供用户无法从现有工具中可靠获得的有意义选择时,才添加这些控件。无论是否提供偏好设置编辑器,页面都必须满足浏览器缩放、文本调整大小、文本间距覆盖、强制颜色和键盘操作的要求。

偏好优先级模型:(1)从无障碍默认设置开始;(2)当网站设置为“System”/“Default”时,遵循已识别的系统/浏览器偏好;(3)仅允许用户明确选择的网站设置覆盖相应的呈现维度;(4)通过“Reset to defaults”移除网站覆盖设置,并恢复对系统设置的遵循。不要将媒体查询匹配结果视为诊断结果——人们选择深色模式、减少动态效果或增强对比度,原因多种多样。


严重程度等级(本技能)

等级含义
严重将覆盖层用作合规替代方案;干扰用户的辅助技术
高未遵循操作系统级偏好(减少动态效果、配色方案)
中个性化控件无法通过键盘访问;状态未播报
低偏好未持久化;未考虑 prefers-reduced-data

严重:切勿将无障碍覆盖层用作合规替代方案

声称能够自动修复问题的第三方“无障碍覆盖层”小组件不得用作合规替代方案。将覆盖层用作合规声明属于严重问题——它们无法修复底层结构问题(缺少标签、ARIA 错误、Tab 顺序不正确),还会主动干扰用户自己的辅助技术(屏幕阅读器、浏览器缩放、操作系统高对比度),造成虚假的合规保证,并广受残障人士群体反对(参见 https://overlayfactsheet.com/)。

偏好设置编辑器与覆盖层不同:它让用户在网站有意设计并测试过的呈现方式中进行选择。个性化不得:声称能让原本无法访问的网站符合规范;在运行时以通用方式重写语义;干扰辅助技术或用户样式;掩盖尚未解决的缺陷;或取代源模板中的修复工作。对于无法改动的旧系统,运行时修复可以作为有记录且经过测试的临时风险缓解措施,但不能视为符合规范,也不能成为停止底层修复工作的理由。


必要结果:区分 WCAG 要求与增强功能

WCAG 通常要求内容能够适应用户设置,而不是要求网站在自定义面板中复现浏览器设置。

要求作者实际必须做到的事项
1.4.4 调整文本大小(AA)不要阻止用户代理调整大小;内容和控件在 200% 缩放时仍可使用。网站提供文本大小控件是一种实现方式,并非普遍要求。
1.4.12 文本间距(AA)允许用户覆盖行距、段落间距、字母间距和单词间距,且不损失内容或功能——网站不必提供间距控件
1.4.10 重排(AA)在规定的窄屏宽度下保留内容和功能
对比度/非文本对比度作者提供的每种主题或预设都必须独立满足适用的标准
减少动态效果在动态效果可能造成障碍时,尊重 prefers-reduced-motion;网站控件可以额外提供覆盖选项
阅读模式、字体选择、密度研究证明有需求时,可作为实用的增强功能——并非自动适用的 WCAG 要求

不要声称添加偏好设置面板就能让不具备无障碍性的内容符合标准。


严重:尊重用户偏好媒体特性(渐进增强)

不支持的查询会被忽略,因此默认呈现必须在没有这些特性的情况下仍可访问。

配色方案
:root {
  color-scheme: light dark;
  --page-background: #ffffff;
  --text-color: #1f2937;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --page-background: #111827;
    --text-color: #f3f4f6;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page-background: #111827;
  --text-color: #f3f4f6;
}

未设置 data-theme 表示“系统”;显式选择则会设置该属性。完整的主题选择器模式请参阅 skills/light-dark-mode/SKILL.md。

减少动态效果

不要应用一条统一规则,强制将每个动画/过渡设置为 0.01ms !important——这种做法可能会破坏状态变化,以及依赖触发 transitionend/animationend 的脚本事件假设。 相反,应移除或替换特定的非必要动态效果:

.panel { transition: translate 200ms ease-out, opacity 200ms ease-out; }

@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion]) .panel { transition: none; }
  :root:not([data-motion]) { scroll-behavior: auto; }
}
:root[data-motion="reduce"] .panel { transition: none; }

如果动态效果传达的是必要状态,应将其替换为即时状态变化——不要移除相关信息。

对比度偏好

prefers-contrast 可以表示 more、less 或 custom——不要把每种匹配都视为用户要求高对比度:

@media (prefers-contrast: more) {
  :root { --border-width: 0.1875rem; --muted-text-color: currentColor; }
}
@media (prefers-contrast: less) {
  .decorative-texture { background-image: none; }
}
@media (prefers-contrast) {
  .decorative-gradient, .decorative-shadow { background-image: none; box-shadow: none; }
}

不带限定值的 prefers-contrast 查询适用于普遍降低视觉复杂度——不适用于强制使用特定的高对比度配色,因为用户可能要求的是较低对比度或自定义配色。

减少透明度和强制颜色
@media (prefers-reduced-transparency: reduce) {
  .dialog-backdrop { background: Canvas; opacity: 1; }
}
@media (forced-colors: active) {
  .button {
    color: ButtonText;
    background: ButtonFace;
    border: 0.125rem solid ButtonText;
  }
  .button:focus-visible { outline: 0.1875rem solid Highlight; }
}

保留默认的 forced-color-adjust: auto;仅对具有自身经过测试的响应的特定元素使用 forced-color-adjust: none——这不是通用的焦点指示器修复方案。Media Queries Level 5 仍是 W3C 工作草案——应将较新的特性视为仍在演进,而非经过测试的默认方案的替代品。


中等:使用无障碍的偏好设置编辑器

选项较少时,优先使用内联 <details> 展开控件——这样无需满足模态框的焦点管理要求:

<details class="display-preferences">
  <summary>Display preferences</summary>
  <form id="display-preferences-form">
    <fieldset>
      <legend>Color theme</legend>
      <label><input type="radio" name="theme" value="system" checked> System</label>
      <label><input type="radio" name="theme" value="light"> Light</label>
      <label><input type="radio" name="theme" value="dark"> Dark</label>
    </fieldset>
    <label for="text-size">Text size</label>
    <select id="text-size" name="textSize">
      <option value="default">Default</option>
      <option value="large">Large</option>
    </select>
    <button type="button" id="reset-display-preferences">Reset to defaults</button>
    <p id="display-preferences-status" role="status"></p>
  </form>
</details>

原生单选按钮和选择框已能呈现选中值——除非测试表明有必要,否则不要为每次视觉变化添加实时区域播报;保存、重置或未保存时显示简短的状态消息即可。入口名称应说明其用途(“显示偏好设置”“阅读设置”),而不是“无障碍”——没有哪个图标能传达所有可能的偏好,因此即使显示图标,也应保留可见的文字标签。

如果确实需要模态框,请实现完整模式:无障碍名称、初始焦点、受限的 Tab 键顺序、按 Escape 关闭、可见的关闭按钮,以及将焦点返回到触发按钮。


中等:使用 CSS 变量应用呈现样式,而非原样存储字符串

:root { --content-measure: 80ch; --reading-line-height: 1.5; }
:root[data-text-size="large"] { font-size: 125%; }
:root[data-reading-layout="comfortable"] { --content-measure: 70ch; --reading-line-height: 1.7; }
.reading-content { max-inline-size: var(--content-measure); }

使用相对尺寸,以便浏览器缩放和用户字体设置继续生效——根元素百分比会根据用户默认值缩放,而非替换默认值。避免使用固定高度的文本容器或裁切,以免在字体、文本大小、语言或间距发生变化时出现问题。

严重:安全地验证、应用和持久化值

在无痕浏览、跨源 iframe 和受限存储环境中,localStorage 不可用——始终使用 try/catch 包裹访问操作。 应用任何存储值之前,都要根据允许列表验证该值——不要将存储的字符串直接插入 CSS 或类名。

const preferenceKey = "site.displayPreferences.v1";
const defaults = Object.freeze({ theme: "system", textSize: "default", motion: "system" });
const allowedValues = Object.freeze({
  theme: ["system", "light", "dark"],
  textSize: ["default", "large", "x-large"],
  motion: ["system", "reduce"]
});

function sanitizePreferences(candidate = {}) {
  const source = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : {};
  return Object.fromEntries(
    Object.entries(defaults).map(([name, defaultValue]) => {
      const value = source[name];
      return [name, allowedValues[name].includes(value) ? value : defaultValue];
    })
  );
}

function readPreferences() {
  try {
    const stored = localStorage.getItem(preferenceKey);
    return stored ? sanitizePreferences(JSON.parse(stored)) : { ...defaults };
  } catch {
    return { ...defaults };
  }
}

function setOptionalAttribute(name, value, defaultValue) {
  if (value === defaultValue) document.documentElement.removeAttribute(name);
  else document.documentElement.setAttribute(name, value);
}

function applyPreferences(preferences) {
  setOptionalAttribute("data-theme", preferences.theme, "system");
  setOptionalAttribute("data-text-size", preferences.textSize, "default");
  setOptionalAttribute("data-motion", preferences.motion, "system");
}

为存储键添加版本号(.v1),并在架构变更时有意迁移或丢弃旧数据——不要尝试解释过时的值。准确说明持久化情况:说“保存在此设备上”,不要说“随你到任何地方”,除非确实提供了账户同步。安全地处理存储被拒绝或数据损坏的情况,并始终提供可用的“重置”功能。


严重:持久化偏好设置,但不要建立隐私档案

只存储重现所选呈现效果所需的值——绝不存储推测出的诊断或残障信息。不要仅仅因为能获取偏好值,就将其发送到分析服务;不要在公开个人资料中暴露偏好;让账户同步成为明确且透明的选择;按照项目的隐私流程说明数据保留和 Cookie 使用情况。用户偏好媒体功能可能导致浏览器指纹识别——尽可能优先使用 CSS 响应,而非通过 JavaScript 读取或传输值。


中等:减少动态效果和干扰,但不要抹去含义

减少动态效果不等于移除所有视觉变化。优先采用:直接切换状态,而非在视口中移动;在仅改变透明度不会造成问题时使用淡入淡出;暂停装饰性动画;为轮播提供手动控制;不使用平滑滚动;保持控件位置稳定。如果动态、闪烁、滚动或自动更新的内容符合 WCAG 2.2.2 的适用条件,请提供“暂停/停止/隐藏”或更新频率控制——不要把这些控件藏在同一个动态效果繁多的组件中。网站级“减少动态效果”设置可以作为 prefers-reduced-motion 的补充;当操作系统设置变化时,“系统”选项必须继续响应。


中等:字体选择与阅读适配

现有证据不支持将某一种字体称为适用于阅读障碍或任何残障的通用最佳字体——不要根据残障告诉用户应该使用哪种字体;让他们根据实际效果自行选择。如果提供字体选项:使用中性描述(无衬线/衬线/等宽);确保覆盖完整的语言和字符;提供可靠的后备字体;保留用户代理的最小字号设置;提供“默认”和“重置”选项。

阅读布局可以限制行长、增加间距、移除装饰性背景、降低信息密度,或调整主要内容与补充内容的顺序——但绝不能悄悄移除说明、警告、错误消息或任务所需信息。如果某项设置会隐藏可选内容,应告知用户隐藏了哪些内容,并提供立即恢复的方式。W3C COGA 指南和 WAI-Adapt 是补充资源,而非额外的 WCAG 2.2 一致性要求。


确保每个主题和预设都能独立访问

每个由作者提供的主题都必须独立满足以下要求:文本对比度;非文本对比度;焦点可见且不被遮挡;已访问链接有明确区分;已选中/已勾选/已展开/当前/错误状态;图表和图标清晰易辨;强制颜色模式下的表现;打印输出。除非某个网站预设是定义明确、经过测试且完整的主题,否则不要将其标为“高对比度”——也不要暗示它等同于操作系统的强制颜色模式。“更高对比度”通常是更准确的标签。


渐进增强与故障处理

即使页面没有增强功能,也必须保持可读且可操作:即使同时提供网站控件,也要使用 CSS 媒体查询;优先使用原生 HTML 控件,而非自定义控件;基本访问不能依赖第三方脚本;不要因远程偏好服务而阻塞渲染;存储失败时保留系统偏好;部分故障后仍应提供重置和恢复功能。


次要:prefers-reduced-data

这是一项新兴媒体查询,可用于在按流量计费的连接下提供更轻量的内容。 目前支持范围有限——请通过 @supports 或特性检测进行保护, 并将其视为面向未来的功能,而非当前要求。

@media (prefers-reduced-data: reduce) {
  .decorative-hero-image { display: none; }
  video[autoplay] { display: none; }
}

测试

  • **默认/失败状态:**在 JS 运行前和禁用 JS 时进行测试;阻止 本地存储,并确认设置仍适用于当前页面;插入格式错误/过时的存储值, 并确认这些值会被忽略;测试首次访问、再次访问、重置、退出登录;确认存储/网络故障 不会阻止内容显示
  • **系统偏好设置:**测试浅色/深色方案,以及页面打开时更改方案的情况(系统模式应跟随变化);测试加载前后对减少动态效果的偏好;测试 prefers-contrast 值(more/less/custom);至少测试一种浅色和一种深色强制颜色调色板
  • **站点控件:**使用键盘、触控、指针和语音输入操作每项设置;使用屏幕 阅读器确认标签/分组/值/焦点/状态;确认应用设置不会导致焦点移动或意外导航; 确认重置会将呈现方式和控件恢复为默认值
  • **内容/布局:**将文本大小调整为 200%;测试 400% 缩放和要求的窄 宽度;应用全部四种文本间距覆盖值;确认控件、 表格、示意图和消息仍可用
  • **组合:**先测试各项单独设置,再测试高风险 组合(超大文本 + 宽松布局、深色主题 + 减少动态效果、显式主题 + 强制颜色、面板打开时缩放至 400%、架构更新后的已存储偏好设置)——采用成对/基于风险的覆盖,而非 穷举组合测试

自动化检查可以验证部分对比度、标签、状态、存储 行为和目标尺寸——但无法判断偏好设置是否易于理解、组合是否会造成认知负荷,或 注入的补救措施是否与辅助技术冲突。可用性测试应纳入使用相关个性化/辅助技术功能的人员。


常见问题

问题修正方法
声称偏好设置控件能让网站符合 WCAG修正源内容;仅将控件描述为可选的个性化功能
声称 WCAG 1.4.12 要求提供间距控件测试用户覆盖设置能否生效且不丢失内容/功能——网站无需提供这些控件
将文字大小按钮视为浏览器缩放的替代品保持缩放功能启用,并独立支持文本调整大小
将所有动画/过渡强制设为 0.01ms !important移除或替换特定的非必要动态效果,且不破坏状态变化
假定 prefers-contrast 始终表示高对比度准确处理 more、less 和 custom
将 forced-color-adjust: none 应用于自定义焦点指示器默认允许强制颜色生效;必要时使用系统颜色
将站点的“高对比度”主题视为强制颜色模式将其作为作者主题进行测试;准确标明其效果
每个页面都添加 A+/A-、字体、颜色、语音和导航控件仅添加经过调研、能够维护和测试的设置
设置图标是唯一标签使用可见文本:“显示偏好设置”
将存储值直接插入类名或 CSS应用前根据精简的允许列表进行验证
假定本地存储永久有效且普遍可用处理拒绝/清除情况;准确说明设备/浏览器适用范围
使用偏好设置值推断残障状况或丰富分析数据仅存储最少的呈现状态
阅读模式在未提示的情况下移除警告或说明保留必要内容;披露任何隐藏的可选材料
只测试单项选项测试高风险组合、重置、迁移和失败状态

完成标准检查清单

  • 不使用第三方无障碍覆盖层来替代合规措施
  • 无需偏好设置编辑器即可使用基本体验
  • 不阻止浏览器缩放、调整文本大小、用户样式、扩展程序或辅助技术
  • 实现 CSS 媒体查询:prefers-reduced-motion(针对具体内容,而非一概设为 0.01ms)、prefers-color-scheme、prefers-contrast(更多/更少/自定义)、forced-colors
  • 任何小组件均标注为“偏好设置”/“显示设置”,而不是“无障碍”
  • 显式的网站选项仅覆盖对应设置;“系统”/“默认”遵循操作系统设置
  • 使用 try/catch 包装 localStorage 访问;根据允许列表验证存储值
  • 在加载时安全地恢复偏好设置;存储键应包含版本号
  • 重置操作会清除网站覆盖设置并更新控件
  • 个性化控件可通过键盘访问,并采用原生语义
  • 将偏好设置数据减至最低,且绝不用于推断残障情况
  • 每种主题/预设均单独满足对比度和状态要求
  • 手动测试每项设置及高风险组合

关键 WCAG 标准

  • 1.4.3 对比度最低值(AA)
  • 1.4.4 调整文本大小(AA)
  • 1.4.10 重排(AA)
  • 1.4.11 非文本对比度(AA)
  • 1.4.12 文本间距(AA)——本技能主要涉及的标准
  • 1.3.6 识别用途(AAA)——将个性化与认知无障碍联系起来
  • 2.2.2 暂停、停止、隐藏(A)
  • 2.3.3 由交互触发的动画(AAA)
  • 2.4.11 焦点不被遮挡(最低要求)(AA)

参考资料

标准展望: WCAG 3.0 正在制定中;个性化要求预计将会扩展,而非缩减。 请关注:https://www.w3.org/TR/wcag-3.0/

评论

支持 Markdown