作为前端/产品工程师,我们每天的大部分时间都在为人们规划和开发产品。因此,考虑到我日常工作的范围,我一直很想知道我的工作和想法如何能让那些使用我们产品的人的世界变得更美好。同理心应该成为每个为人类设计和开发产品的人的核心技能和思维方式。这种核心技能使我们能够为不同于我们的人创造产品,并创造出符合他们特定需求的产品。
如果您正在思考最后一句话,那么不妨以路缘切口效应为例:路缘切口是一个放置在路缘上的小斜坡。这项创新背后的理念可以追溯到 20 世纪 70 年代,最初是为了帮助轮椅使用者更安全地过马路而开发的。
这一简单的创新促使路缘石成为城市设计中的标准配置,不仅为轮椅使用者的日常生活提供了帮助,还改善了携带婴儿车的父母、携带滚动行李的旅行者等的行动能力。你现在可能在想,城市设计专家当初怎么就没有把它作为一项标准功能呢?
这正是包容性设计所要解决的问题:当我们承认我们的能力是我们开发产品的基线时,我们就会让一些人很容易使用这种产品,但却把其他人排除在外。
根据我的亲身经历,当你开始意识到这个世界仍在以残疾为由排斥他人的时候,你就不会再用以前的眼光看待这个世界了,你会突然变得更加关注周围的环境。
第 I 部分:网络无障碍要点
我们谈到了包容性设计以及它与无障碍设计的关系。但无障碍性究竟是什么呢?我们可以将无障碍性视为一种包容性。无障碍性是指残障人士可以使用产品的程度。其目的是消除障碍,创造解决方案,让残障人士也能访问和使用我们的产品。还必须提及的是,残疾一词有不同的含义:它可以是永久性的(如盲人)、暂时性的(如手臂受伤的人)或情境性的(如父母用一只手抱着孩子)。
尽管这并不是一份详尽的清单,但网络无障碍包含了所有影响用户访问网络的残疾:听觉、视觉、认知、神经、肢体、语言和视力障碍。不过,如前所述,在数字产品中执行标准也有助于非残疾人士,例如,因年龄增长而能力发生变化的老年人、生活在互联网连接速度慢或带宽昂贵的国家的人等等。要想对这一主题有更深入的了解,我邀请您观看视频 “网络无障碍视角”。
在本文中,我们将更多地关注网络无障碍性的子集,即数字产品在多大程度上可以被尽可能多的人使用。
除了开发人人都能使用的无障碍产品之外,无障碍性并不是团队的首要任务,这一点很常见。然而,转变对这一问题的看法不仅能帮助您的最终用户,还能帮助您的企业:
- 可访问性会对应用程序的搜索引擎优化(SEO)产生重大影响。一个网站如果能让更多用户使用,自然会提高用户对内容的参与度,降低跳出率,提高对话率,从而提高搜索引擎优化效果。具有良好语义结构 HTML 代码的无障碍网站也更容易被搜索引擎爬虫发现,从而提高网站搜索引擎优化的相关性;
- 提高客户满意度和品牌声誉:当一个网站比其他竞争对手更容易访问时,企业的市场份额和影响力就会增加,从而提高收入。最终,您的企业不仅会拥有竞争优势,而且还有机会为残疾人带来改变,不仅考虑到您为他们的生活带来的影响,而且还展示了您对包容性、多样性和社会责任的承诺;
- 法律合规性:在某些国家和行业,无障碍数字产品已经成为一项法律要求。通过遵守这些法律,你可以避免潜在的法律处罚,避免被起诉。不过,请记住,出于法律原因让更多人使用您的产品不应是您唯一或主要的关注点–我们的目标始终应该是以人为本。
关于最后一点,每个国家都有不同的合规标准和法规。如果您想了解无障碍网络局提供的有关无障碍网络诉讼的数据,请点击以下链接:
- 2021 年,针对美国企业的网络无障碍诉讼达 2352 起(比 2020 年增加了约 14%);
- 最受关注的行业是消费品、服务和零售业,共有 955 起数字无障碍诉讼;
- 根据非营利组织 WebAIM 的分析,互联网上排名前 100 万的网页中有 97.4% 存在可检测到的 WCAG 2.0 故障。
在欧洲,2016 年通过了《欧盟网络无障碍指令》,该指令规定公共网站和应用程序必须更加无障碍。该指令于2021年6月全面生效。不过,私营部门将有三年的时间来遵守这一标准,直到 2025 年 6 月。
这些国际标准是通过采用《网页内容可访问性指南》(WCAG)制定的,该指南是由万维网联盟(W3C)发布的一个包含原则、指南和检查点的框架。通过遵守最新版本的《无障碍网页内容指引》,我们可以确保我们的应用程序符合这些标准。WCAG 目前为 2.1 版,分为 3 个级别: A、AA 和 AAA。
WCAG 基于四项原则,为任何人访问和使用网络内容奠定了基础: 可感知(Perceivable)、可操作(Operable)、可理解(Understandable)和稳健(Robust)。WCAG 认为,如果这些原则中有任何一条不正确,那么残疾用户就无法使用网络。我邀请您进一步阅读有关 WCAG 的资料,以全面了解这一领域的工作。
为了全面了解某个国家或地区在无障碍立法方面的最新情况,万维网联盟有一个网页按地区列出了政府政策。
第二部分:创建无障碍电子商务表单
Radix 基元和无障碍简介
作为一个创造数字技术的人,重新转变思维方式,重新思考如何构建和开发产品,比学习一个新的工具或框架更具挑战性。不过,如今开发人员拥有一系列工具,可以确保在开发阶段一开始就考虑到可访问性。
在本文中,我们将特别关注使用 Radix Primitives 构建可访问的 React 表单。本教程还假定您已熟练掌握 React、Tailwind 和 Typescript。不过,请记住,这只是一个让您构建更具包容性和可访问性表单的可能工具。大多数 UI 组件库在发布时都会将可访问性放在首位。然而,确保网络可访问性标准是一个过程,并不是只有使用这些工具才能实现;这些都是这个过程的一部分。
如果你想了解其他组件库,我邀请你阅读更多关于 Chakra UI 的内容,这是一个模块化的无障碍库,我个人非常喜欢使用它。我还有机会阅读了 React Aria,这是 Adobe 为 React 开发的一个以无障碍为重点的软件包;不过,这个库有一个很大的不同:它并不以组件为重点,而是使用了基于钩子的 API。
关于 Radix Primitives,这是一个开源组件库,专注于无障碍网络应用程序,并提供一套无障碍的底层组件。该库的组件遵循 WAI-ARIA 框架,处理许多与可访问性相关的实施细节。您还可以查看该库的可访问性文档概览。
与其他库不同,Radix Primitives 有一个特点:它采用渐进式采用。这意味着每个基元都可以单独安装,而不是安装所有库组件。基元也是独立版本的,以便于增量采用。
无障碍测试
如果你想知道其他电子商务网站是如何解决无障碍问题的,我请你做的一个练习就是打开屏幕阅读器(如 Mac 上的 VoicerOver),进入你喜欢的电子商务网站,尝试购买产品并结账。请记住,您应该尽可能模拟特定障碍的环境,例如盲人或视力受损的用户。这就意味着,你将通过各种键盘命令(如方向键、Tab、Shift+Tab 和其他命令)来移动光标,同时屏幕阅读工具会公布光标的位置。如果你成功完成了最后一步,那么恭喜你!你最喜欢的电子商务确实将无障碍作为优先事项,这是我们应该庆祝和鼓励的。
我建议您的第一步是使用屏幕阅读器精确测试您的应用程序,以了解视障用户如何浏览您的菜单。不过,请记住,你是作为网站的建设者在使用你的网站,所以一定要克服自己对正在建设的产品的偏见。
关于自动化工具,我将在本文中提到几个,即 Axe、WAVE 和 Lighthouse。这些工具都是免费提供的,它们是开始测试应用程序无障碍问题的重要起点:
- Axe 是 Deque 创建的一套工具,旨在为测试库提供解决方案。要使用 Axe,其中一个可行的方法是安装 Axe DevTools,这是一个浏览器扩展,可为您提供测试应用程序无障碍问题的方法。要开始使用 Axe DevTools 测试无障碍性,只需打开浏览器的 “开发工具”,导航到 Axe DevTools 标签,然后在所需网页上运行分析即可;
- WAVE 是一套评估工具,可帮助开发人员提高网站的可访问性。运行该工具有两种可能的方法:使用表单,只需输入网页地址并提交表单;或安装浏览器扩展。这两种方式都能提供最重要的发现摘要,如对比错误、警报、功能、ARIA 元素等。
- 灯塔分析网页应用程序和页面,收集现代性能指标和开发人员最佳实践的见解。它是一款开源的自动化工具,你可以使用 Chrome DevTools 中的 Lighthouse 运行,从而进行性能、最佳实践、搜索引擎优化、PWA 和可访问性审核等审计。该工具使用 WCAG 准则执行可访问性审核。
然而,重要的是要考虑到,虽然这些工具在检测无障碍性问题方面非常有用,但它们并非完全万无一失,这意味着它们可能无法识别所有可能的无障碍性问题。确保整个无障碍测试的最佳方法是确保残疾人也能参与测试过程。
使用 Radix Primitives 和 Tailwind 创建无障碍表单
每当我在没有产品经理或设计师帮助的情况下创建用户界面时,将用户面临的具体使用情况可视化对我构思结果有很大帮助。
为此,我尝试创建一个基本的线框来帮助我理解我想要实现的目标,如下所示。在本教程中,假设我们有一个销售植物的电子商务网站,我们的重点是创建一个结账表单:
我们为什么要关注结账流程?如果用户在购买过程中遇到任何困难,尤其是如果技术不允许用户完成这一步,那么这个特殊时刻就会给公司带来一些潜在的后果:
- 用户可能会放弃结账流程。举例来说,设想一个使用案例,视障用户无法使用屏幕阅读器浏览您的网站–这会造成挫败感,并有可能放弃购买;
- 销售损失。结账过程中的无障碍障碍可能会导致公司的收入损失,将您的产品拒之门外;
- 法律后果,视企业所在地而定;
- 损害公司声誉。
为了确保结账流程尽可能无障碍,我们需要在功能上确保一些关键目标:
- 结账过程应仅通过键盘完成;
- 表单应有正确、准确的说明和标签;
- 图像和颜色不应是传递信息的唯一方式(例如,如果用户输入了错误的字符,表单就会变成红色,而没有任何其他信息,色盲用户(如 Deuteranopia)可能会难以理解发生了什么,因为他们看到红色的方式与非色盲用户不同);
- 应保证移动设备的响应速度。
至此,我们已经万事俱备,可以开始考虑构建我们的结账表单了。
要开始构建表单,我们需要启动一个使用 React 和 Typescript 的新 Vite 项目:
$ npm create vite@latest reacting-to-a11y-article -- --template react-ts $ cd reacting-to-a11y-article $ npm install $ npm run dev
为了给页面提供一些布局,我将使用 Tailwind,但也可以随意为你的网络应用程序设计你认为合适的样式。
如果你不想经历设计应用程序样式的麻烦,而想直接跳转到表单部分,可以克隆或fork包含本教程的 GitHub repo,直到这一部分和所有样式都已配置好。这样,您就可以在已经应用了一些样式的情况下启动网络应用,并开始应对构建无障碍结账表单的挑战。
由于样式并不是本文的重点,我将只关注表单部分,所以请随时查看网络应用程序在此之前的样式。
主分支包含所有必要的代码,您可以开始项目工作,主要布局和组件已经创建。
不过,如果你想跳转到包含所有已创建内容的最终项目,请导航到最终分支。
如果你决定克隆或分叉 repo,并且你在主分支上,你会看到这个界面:
这意味着我们从现在开始要做的工作就是添加 Radix Primitives 组件,并确保我们的表单尽可能易于访问。
正如您在线框中看到的,我们将要求用户提供一些数据,以便完成结账流程。
要开始制作表单,首先要在命令行中安装表单组件:
$ npm install @radix-ui/react-form
从现在起,我们可以开始使用 Radix Primitives 的表单组件了。
为此,请在 components/checkout/form 文件夹中创建一个新的 .tsx 文件,并导入新安装的组件:
import * as Form from ‘@radix-ui/react-form’;
Radix 已经为开发者提供了组装无障碍表单所需的所有必要组件,我们的工作应该是思考如何处理这个问题。
首先,我们可以从最简单的部分开始:询问名字和姓氏。这些输入不一定很复杂,但应该遵守一些规则(如字符数、特殊字符验证等)。
因此,我们首先要在功能组件中添加必要的字段以及一些样式:
import * as Form from "@radix-ui/react-form"; type UserInfoProps = { type: "first" | "last"; }; function UserInfo({ type }: UserInfoProps) { const errorMessageStyle = "text-[10px] text-red-700 font-bold opacity-80"; const formLabel = `${type.charAt(0).toUpperCase()}${type.slice(1)} Name`; return ( <Form.Field name={`${type}name`}> <Form.Label className="text-sm font-bold">{formLabel}</Form.Label> <Form.Control asChild> <input className="mt-1 block w-full px-3 py-2 border-2 rounded-md text-sm shadow-md border-fernGreen" type="text" placeholder={`Your ${type} name`} pattern="^[a-zA-Z0-9 ]*$" required /> </Form.Control> <Form.Message className={errorMessageStyle} match="valueMissing"> {`Please enter your ${type} name.`} </Form.Message> <Form.Message className={errorMessageStyle} match="patternMismatch"> Please enter only alphanumeric characters and spaces. </Form.Message> </Form.Field> ); } export default UserInfo;
进一步看一下这段代码,我们使用 Field 作为表单所有元素的包装:标签负责标注表单,而控件则用于呈现输入字段,它是一个 HTML 输入元素,具有占位符、类型等常用属性。消息组件用于在某些条件出现时显示错误信息(一个是输入框为空时,另一个是输入框包含非字母数字或空格字符时)。
表单确实是一个棘手的问题,因为开发人员需要考虑很多问题。表单有非常复杂的验证要求,需要在不同浏览器之间保持一致,用户体验应该是无缝的,同时还要满足可访问性要求。
到此为止,我们只有两个字段:
如何确保这些都是无障碍的?一种可能的方法是打开 VoiceOver,看看界面是如何解释的: 能否使用制表符键在元素之间移动?是否需要使用指针设备?你的表单是否给出了正确的提示,让用户完成所有必要信息的填写?您还可以使用 WAVE 工具,确保没有检测到重大的无障碍问题;除了 WAVE 之外,您还可以尝试使用 Axe 工具,确保没有检测到问题。
在其他字段方面,我们还应该要求填写用户地址和其他字段,如邮政编码和城镇/城市:
import * as Form from "@radix-ui/react-form"; function UserAddress() { const errorMessageStyle = "text-[10px] text-red-700 font-bold opacity-80"; return ( <Form.Field name="address1"> <Form.Label className="text-sm font-bold">Shipping Address</Form.Label> <Form.Control asChild> <input className="mt-1 block w-full px-3 py-2 border-2 rounded-md text-sm shadow-md border-fernGreen" type="text" placeholder="Your street address" required /> </Form.Control> <Form.Message className={errorMessageStyle} match="valueMissing"> Please enter your street address. </Form.Message> </Form.Field> ); } export default UserAddress;
import * as Form from "@radix-ui/react-form"; function UserPostalCode() { const errorMessageStyle = "text-[10px] text-red-700 font-bold opacity-80"; return ( <Form.Field name="zip"> <Form.Label className="text-sm font-bold">Postal Code</Form.Label> <Form.Control asChild> <input className="mt-1 block w-full px-3 py-2 border-2 rounded-md text-sm shadow-md border-fernGreen" type="text" placeholder="e.g. 10001" required pattern="^\d{5}$" /> </Form.Control> <Form.Message className={errorMessageStyle} match="valueMissing"> Please enter your postal code. </Form.Message> <Form.Message className={errorMessageStyle} match="patternMismatch"> Please enter a US postal code in the format of five digits. </Form.Message> </Form.Field> ); } export default UserPostalCode;
import * as Form from "@radix-ui/react-form"; function UserCity() { return ( <Form.Field name="city"> <Form.Label className="text-sm font-bold">Town/City</Form.Label> <Form.Control asChild> <input className="mt-1 block w-full px-3 py-2 border-2 rounded-md text-sm shadow-md border-fernGreen bg-gray-200" type="text" value="New York" placeholder="e.g. New York" disabled /> </Form.Control> </Form.Field> ); } export default UserCity;
import * as Form from "@radix-ui/react-form"; function UserCountry() { return ( <Form.Field name="country"> <Form.Label className="text-sm font-bold">Country</Form.Label> <Form.Control asChild> <input className="mt-1 block w-full px-3 py-2 border-2 rounded-md text-sm shadow-md border-fernGreen bg-gray-200" type="text" value="United States" placeholder="e.g. United States" disabled /> </Form.Control> </Form.Field> ); } export default UserCountry;
在完成这些领域的工作后,您应该会得到一个更接近这个方案的解决方案:
现在,我们已经完成了本教程所需的大部分字段的创建工作,那么如何确保这个界面整体上是无障碍的呢?
一种可能的方法是打开 VoiceOver,看看界面是如何解释的: 能否使用制表符键在元素之间移动?是否需要使用指针设备?您的表单是否提供了正确的提示,让用户完成所有必要信息的填写?使用 VoiceOver 或其他屏幕阅读器是一种很好的方法,可以让视障用户感受到界面的声音。
您还可以使用 WAVE 工具,确保没有检测到重大的无障碍问题;除了 WAVE 之外,您还可以尝试使用 Axe Tools,确保没有检测到任何问题。
运行这些工具后发现,该界面总体上遵循了无障碍方面的最佳实践:
不过,我想提醒大家的是,可访问性指南有助于保证整个网络的标准,但您的界面应该由残疾用户进行测试;请记住,由于我们正在构建自己的产品,我们会有一种偏见,认为如果这些工具没有指出明显的问题,那么一切都应该是好的。包容意味着要能够超越我们的认知和偏见,考虑到其他人可能不会以与我们相同的方式来看待我们的产品。
闭幕词
无障碍性不应是一个人的工作。打造具有包容性和无障碍性的数字体验是一项团队工作:开发人员、设计师、产品经理、利益相关者等等。
尽管开发人员已经有了一套工具,可以根据无障碍性指南和最佳实践对他们的应用程序进行全面测试,但最终,确保我们的产品具有包容性的最好方法还是让残障用户试用,看看我们在开发产品时没有考虑到他们的哪些需求,以及如何对其进行改进。我们在构建产品时考虑到的每一个细节都旨在解决无障碍问题,这对用户来说是领先了一步,也是我们在开发数字产品时应该追求的目标。
本文仅涉及电子商务平台如何改进产品、实现包容性并考虑残疾用户的一个很小的方面。正如我们在前面的介绍部分所讨论的那样,将包容性原则作为一项标准,可以让每个人都从中受益–这不仅会让你的企业免于诉讼,而且会有更多的人喜欢你的产品,而这应该是保证无障碍性的主要重点:创造让每个人都能享受和贡献的产品。
无障碍设计和包容性设计共同作用,确保我们的产品符合标准,人人可用。全球约有 16% 的人口患有某种形式的残疾。因此,请记住 并非所有的残疾都是可见的💡。我们需要确保能够反思自己的偏见,以创造一个包容的数字世界。