知识

跨市场无障碍审计:测试每个国家用户实际看到的内容

对美国首页的审计几乎说明不了你的德国或日本首页的情况。我们审计了来自四个国家的23个网站:四分之一存在仅特定市场才有的问题。

James Meadow

James Meadow

2026年10月4日 · 3 分钟阅读

大多数无障碍测试只针对网站的一个版本:团队每天构建和查看的那个版本,通常是英文,通常来自办公室。但一个拥有十几个市场的网站实际上是十几个不同的网站。翻译会改变文本长度和换行方式,当地团队会添加自己的横幅和表单,不同国家会出现不同的组件,而柏林或东京访客获得的版本可能从未被测试过。

我们想知道这在实践中究竟有多重要。于是我们选取了23个大型多市场网站,分别从美国、德国、法国和日本境内加载其对应的美国、德国、法国和日本版本,并对所有版本运行了相同的自动化无障碍审计。本指南将分享我们的发现、所用的代码,以及如何将市场感知测试纳入你自己的流程。

关键要点

  • 你测试的版本并不是每个人都会获得的版本。在结果稳定的20个网站中,有5个网站在本地化版本中存在至少一种从未出现在美国版本中的无障碍故障类型。
  • 这些差异是具体的:注册表单上未标注的生日字段、没有标签的搜索框、没有文字替代的图片、未命名的按钮,以及对比度不达标的文本。
  • 页面在不同访问之间会发生变化,因此应先测量噪声。23个网站中有3个在相隔几分钟的两次同一美国页面加载中显示出不同的结果。
  • 自动化规则只能发现问题的一部分。应将其视为逐市场的回归检测网,并继续保留辅助技术的人工测试。
  • 在欧盟,《欧洲无障碍法案》自2025年6月28日起已适用于包括电子商务在内的许多消费服务,这使得每个市场版本都成为合规范围的一部分。

为什么一个版本还不够

市场之间有几件事会发生变化,这些变化都可能影响无障碍性:

  • 文本。 德语单词较长,日语文本使用不同的字体和换行方式,翻译后的标签可能丢失、重复或留空。
  • 组件。 同意横幅、Cookie 墙、年龄验证、货币和国家选择器、本地支付小部件以及区域性促销活动往往只出现在部分市场。
  • 内容。 当地营销团队会发布自己的图片和活动,有时在主设计系统之外,而替代文字往往是最先缺失的内容。
  • 交付方式。 有些网站会针对不同地区提供不同的构建版本、域名或内容管理实例。

这些版本具体是什么样子,取决于访客所在的位置。如果从美国办公室加载德语页面进行测试,可能会被重定向、看到不同的同意流程,或者看到某个区域组件的美国版本。要测试德国用户实际获得的内容,测试就必须以德国访客的身份运行。

我们如何测试

我们选取了发布美国英语、德语、法语和日语主页版本的大型网站,这些网址取自各网站自身的hreflang 标注。在2026年10月4日,我们通过与对应国家匹配的 Shifter 出口,在 Chromium 中加载每个版本,并将浏览器的语言和时区设置为匹配:美国为纽约,以及柏林、巴黎和东京。我们等待五秒钟以等待客户端渲染和同意横幅出现,然后运行了带有 WCAG 2 Level A 和 AA 规则的 axe-core 4.13。

我们最初选取的25个网站中,有2个在每个市场都返回了拦截页面,因此被排除,剩下23个。为了测量噪声,我们对每个美国页面审计了两次。23个网站中有3个在这两次美国运行之间给出了不同的结果,通常是因为轮播横幅或随机加载的内容,因此在比较各市场时我们排除了这三个。

我们的发现

衡量指标美国,第一次运行美国,第二次运行德国法国日本
23个网站的违规实例数158165174168161
未检测到违规的网站数65335
每页平均违规类型数1.61.71.81.81.7

本地化版本在每项指标上都略差一些,但在这个层面上的差距接近于运行间的噪声。更清晰的信号在于哪些问题出现在哪里。在结果稳定的20个网站中,有5个网站在本地化版本中存在至少一种既未出现在第一次也未出现在第二次美国运行中的故障类型:

网站类型仅在美国之外发现的故障市场
游戏平台注册生日字段(日、月、年)没有可访问名称德国、法国、日本
网站建设工具主搜索字段没有标签德国、法国、日本
安全软件供应商货币选择器含有无效的 ARIA 属性;一张没有文字替代的促销图片;一个未命名的视频播放按钮德国、法国、日本
电子商务平台一个没有可访问名称的按钮德国、法国
开源项目网站页脚文本颜色对比度不达标德国、法国、日本

其中几项的重要性超出了数量所显示的程度。屏幕阅读器用户无法完成日期字段没有名称的注册表单,也无法使用仅被播报为”编辑文本”的搜索框。这类故障正是只测试美国页面的团队永远看不到的。

在全部92次审计中,最常见的故障是颜色对比度,在43个页面上发现,其次是没有可访问名称的按钮和没有文字替代的图片。

代码

下面这个模块会以某个市场访客实际看到的方式审计一个页面,并标记拦截页面或错误页面,以免将其误认为你想测试的页面。它需要 Playwright 和 axe-core。

import { readFileSync } from 'node:fs';
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const AXE_SOURCE = readFileSync(require.resolve('axe-core/axe.min.js'), 'utf8');

// Audit one page as a visitor in one market would see it: the browser's locale and time zone match the
// market, and the browser itself runs through an exit in that country.
export async function auditPage(browser, url, { locale, timezoneId }) {
  const context = await browser.newContext({ locale, timezoneId });
  const page = await context.newPage();
  try {
    const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
    await page.waitForTimeout(5000); // let client-side rendering and consent banners appear
    await page.evaluate(AXE_SOURCE); // evaluate, not a script tag, so the page's CSP cannot block it
    const result = await page.evaluate(() =>
      window.axe.run(document, { runOnly: ['wcag2a', 'wcag2aa'], resultTypes: ['violations'] }));
    const lang = await page.evaluate(() => document.documentElement.getAttribute('lang'));
    const status = response ? response.status() : null;
    return {
      url,
      finalUrl: page.url(),
      status,
      blocked: status === null || status >= 400, // a block or error page, not the page you meant to audit
      title: await page.title(),
      lang,
      violations: result.violations.map((v) => ({ id: v.id, impact: v.impact, nodes: v.nodes.length })),
    };
  } finally {
    await context.close();
  }
}

以下是针对单一市场运行该模块的方式,浏览器通过该国家的出口进行路由:

import { chromium } from 'playwright';
import { auditPage } from './audit.mjs';

// One browser per market, running through an exit in that country.
const browser = await chromium.launch({
  proxy: {
    server: 'http://p.shifter.io:443',
    username: `${process.env.SHIFTER_PROXY_USER}-country-de`,
    password: process.env.SHIFTER_PROXY_PASS,
  },
});
const result = await auditPage(browser, 'https://shifter.io/de', { locale: 'de-DE', timezoneId: 'Europe/Berlin' });
console.log(result.status, result.blocked, result.lang, result.violations);
await browser.close();

针对我们自己的德语主页运行后,报告显示没有违规。

构建过程中沉淀了两个经验教训。blocked 标志的存在是因为我们第一次运行时审计了拦截页面:有两个网站拒绝了所有出口,其拦截页面产生了看似可信的结果,其中包括一个被声明为美国英语的页面,我们曾一度将其误认为是标签错误的德语页面。此外,axe 是通过 evaluate 而非 script 标签注入的,因为某些网站上严格的内容安全策略会拒绝注入的脚本。

将其纳入你的流程

  • 对你销售的每一个市场,从该市场本地进行审计。 使用每个国家的出口,并匹配语言和时区,方法如匹配代理地理位置、时区和语言中所述,使审计看到的同意流程、重定向和区域组件与当地访客所见一致。
  • 从网站本身找出各个版本。 Hreflang 标注列出了每个市场版本,因此随着市场增加,审计列表也能保持完整。
  • 在信任差异之前先测量噪声。 对同一页面审计两次,并将在完全相同的两次运行之间也出现的变化视为噪声。
  • 检查你审计的是否是正确的页面。 记录状态码、标题和最终网址,并丢弃拦截页面、错误页面以及重定向到另一个市场的情况。我们的反机器人技术栈检测解释了为什么仅凭状态码可能会产生误导。
  • 与主版本进行对比。 报告那些存在于某个市场版本但不存在于团队测试版本中的故障,因为这些正是无人发现过的问题。
  • 按计划定期运行。 本地活动和横幅每周都会变化;变更检测的原则同样适用于无障碍性。
  • 让人工始终参与其中。 W3C 明确指出,工具无法检查所有无障碍要求,仍需要人工判断。自动化审计能发现回归问题,但并不能证明一个网站是无障碍的。

为什么现在这一点很重要

长期以来,无障碍性一直是许多国家公共部门网站的法律要求。在欧盟,《欧洲无障碍法案》自2025年6月28日起已适用于一组特定的消费类产品和服务,包括电子商务,而用于满足该法案的统一欧洲标准正是建立在 WCAG 之上。对于一家在欧洲各国销售产品的公司而言,其网站在每个国家的版本都属于必须满足这些要求的范围,而不仅仅是开发人员查看的那一个版本。这是一般性信息,并非法律建议;请就适用于你每个市场的具体规定咨询法律顾问。

总结

无障碍性通常只在一个地方进行测试,却要交付给许多地方。在我们对23个多市场网站的审计中,在结果稳定的网站里,有四分之一存在仅出现在美国之外的故障,从未标注的注册字段到没有文字替代的图片,不一而足。

像当地访客那样测试每个市场版本,将真实差异与噪声区分开,并与团队已经检查过的版本进行对比。每个市场只需花费几分钟的自动化测试时间,就能发现当地用户一直以来都在遇到的问题。

来源与参考资料

准备好开始了吗?

试用 Shifter 住宅代理,205M+ 个 IP,195+ 个国家,低至 $0.10/GB。

立即开始