支持详解:跨平台可访问组件的设计与源码实现)
设计系统前端开发工具UI组件【免费下载链接】LonaA tool for defining design systems and using them to generate cross-platform UI code, Sketch files, and other artifacts.项目地址https://gitcode.com/gh_mirrors/lo/Lona点击查看免费下载导读Lona 是一个用于定义设计系统、并据此生成跨平台 UI 代码、Sketch 文件等产物的工具。本文将围绕官方文档 studio/docs/accessibility.md 展开系统讲解 Lona 提供的跨平台无障碍Accessibility参数体系如何用可视化的方式为组件构建可被屏幕阅读器、键盘等辅助技术assistive technologies正确识别的交互界面如何通过accessibilityType精确控制元素顺序与焦点行为以及当内置参数不够用时如何直接操作底层原生视图。读完本文你将掌握 Lona 组件无障碍化的完整配置流程、每一个无障碍参数的取值与语义以及 iOS、WebReact DOM、React Native 三端各自的原生实现细节与扩展手段。一、为什么需要一套跨平台的无障碍参数在传统开发中iOS 使用UIAccessibility/accessibilityLabel系列属性Web 使用 ARIA 与tabindexReact Native 又提供自己的一套accessibility*props。三套体系命名相似但语义各异跨平台复用设计系统时很难保持一致。Lona 的解法是在层Layer之上抽象出一套平台无关的无障碍参数由编译器负责把它们翻译成各平台的原生实现。文档明确指出这些参数modeled after iOS and React Native accessibility support以 iOS 与 React Native 的无障碍支持为蓝本。从编译器源码可以印证这套抽象的真实存在parameterKey.re 中内置了 8 个无障碍相关的参数键accessibilityType、accessibilityLabel、accessibilityHint、accessibilityValue、accessibilityRole、accessibilityElements、onAccessibilityActivate、accessibilityChecked而 accessibility.re 定义了核心类型type accessibilityElement {label: option(string)}; type accessibilityType | Auto | None | Element(accessibilityElement) | Container(list(string));可以看到Element携带一个accessibilityElement包含 label 等信息Container携带一组子层名称字符串。这套类型正是下文各参数的底层模型。二、实战指南让一个组件变得可访问文档给出的标准流程适用于绝大多数 Lona 组件核心思路是**顶层容器 逐层元素**的两级配置1. 将顶层图层设为 accessibility Container在组件中选中顶层图层通过Type下拉框将其无障碍类型设置为Container容器。容器本身不被辅助技术朗读它的作用是圈定一组可访问子元素的边界。2. 用 Elements 编辑器定义元素名称与顺序在Elements编辑器中按你期望的朗读顺序把需要暴露给辅助技术的子图层名称逐条列出。这一操作会覆盖系统默认的元素顺序从而实现对可访问元素顺序的精确控制。3. 为每个子图层配置 Element 属性回到图层列表中逐个选中上一步指定的子图层将其Type设置为Element元素然后按需添加无障碍标签Label、提示Hint等参数。文档特别强调一个本地化实践Label和Hint通常应当通过 Lona Logic逻辑来赋值而不是写死静态字符串——这样每个值都可以作为组件的参数传入从而在不同语言环境下被本地化。这意味着你需要在组件上为每个需要本地化的文本新增一个参数。与源码的对应关系这一流程在数据模型层面完全自洽。Models/Accessibility.swift 中的AccessibilityType枚举与编译器的 accessibility.re 一一对应auto对应default、none、element(AccessibilityElement)、container([String])并提供了withType、withLabel、withHint、withRole、withElements等链式修改方法供 Studio 检查器Inspector在编辑时逐步构造完整配置。而 parameterKey.re 中的字符串映射如accessibilityType AccessibilityType则保证了.component文件、Studio 与编译器三方的参数名称完全一致。三、无障碍预览Accessibility Overlay配置完成后如何验证元素顺序是否正确Lona Studio 提供了实时预览从主菜单打开View Accessibility Overlay画布上会以带序号的描边矩形标出每个可访问图层的位置与朗读顺序该顺序同时对应 Web 端的 focus ring 与 iOS 端的 VoiceOver 轮廓。其底层实现位于 AccessibilityOverlay.swiftdraw(_:)方法遍历accessibilityOrderRects为每个矩形绘制 3px 白色外描边与 1px 黑色内描边并在矩形右上角绘制黑底白字的序号标签。需要注意该预览是近似值如果元素顺序已被精确指定例如按上文指南配置了accessibilityElements预览结果就是精确的如果某些图层的accessibilityType为default预览不会显示它们但底层平台仍可能将其暴露给辅助技术。从编译器侧的 javaScriptLayer.re 可以解释这种精确性的来源Hierarchy.accessibilityElements会递归遍历图层树——Auto层继续下钻子层Element层直接收拢为可访问元素Container层则按accessibilityElements数组中的名称查找对应的子层Layer.findByName并展开其子树。换句话说预览顺序就是编译器将要生成的实际顺序。四、无障碍参数全解析Lona 支持的图层无障碍参数中有些是**静态static的、有些是动态dynamic**的、有些两者皆是静态参数可以在编译期为它指定默认值动态参数可以在运行时通过 Lona Logic 赋值例如根据组件参数或状态切换标签文本、选中状态等。下面逐一说明各参数的语义支持平台、类型、默认值与注意事项均以官方文档为准并结合源码佐证。4.1accessibilityType静态支持平台iOS 与 Web类型default|none|element|container默认default语义该参数是Lona 独有的抽象不直接翻译为任何平台属性而是由 Lona 用来设置其他平台特定参数。四种取值的行为取值行为default使用平台默认值。例如 Text 图层会自动把文本内容当作accessibilityLabel。文档建议优先显式使用none/element/container而不是让平台去猜。none该图层对辅助技术完全隐藏。element该图层可被辅助技术聚焦。Lona Studio 要求先设置此项才会显示AccessibilityLabel等大部分其他参数。container该图层包含可访问的后代图层可通过accessibilityElements参数按 id 配置。源码印证编译器 accessibility.re 的accessibilityType变体与之一一对应而Element变体中携带的accessibilityElement结构含label字段正是element类型下可继续配置的附属信息。4.2accessibilityLabel静态 动态支持平台iOS 与 Web类型String语义当用户聚焦该图层时屏幕阅读器会朗读这段文本。它取代了默认的图层文本内容是元素最重要的可访问信息。4.3accessibilityHint静态 动态支持平台目前仅 iOS类型String语义屏幕阅读器在读完accessibilityLabel及其他信息后会接着朗读这段提示文本用于说明元素的使用方式例如double tap to add to cart。4.4accessibilityValue动态支持平台目前仅 iOS类型String语义用于交互式控件。例如一个数字输入框应把当前数值设置为accessibilityValue让屏幕阅读器能读出控件的实时值。之所以设计为动态参数正是因为当前值通常是运行时状态。4.5accessibilityRole静态支持平台目前仅 iOS类型none|button|link|checkbox|search|image|keyboardkey|text|adjustable|imagebutton|header|summary语义这些预设决定了图层的高层行为。文档注明该列表取自 React Native对移动端适配良好但 Web 端可能还需要补充更多角色。源码印证Studio 模型 Models/Accessibility.swift 中的AccessibilityRole枚举与该列表完全一致enum AccessibilityRole: String { case none, button, link, checkbox, search, image, keyboardkey, adjustable, imagebutton, header, summary }角色映射细节Role mapping detailscheckboxWeb映射为checkbox角色并允许accessibilityChecked参数通过 Logic 赋值。iOS映射为button角色。此时应使用accessibilityValue控制屏幕阅读器的朗读内容例如把accessibilityValue设为checked/unchecked的本地化翻译。4.6accessibilityChecked静态支持平台Web类型Boolean语义当图层的accessibilityRole为checkbox时可通过 Logic 为该参数赋值表示复选框是否处于勾选状态。4.7accessibilityElements静态 动态†支持平台iOS 与 Web类型ArrayString语义需在accessibilityType设为container之后设置。它列出了辅助技术应当朗读的后代图层名称列表数组中出现的每个图层通常还需要把自己的accessibilityType设为element文档原文此处写作 elements结合上下文与源码应为 element见 accessibility.re 中Element变体。† 特殊说明该参数只能被赋值为硬编码字符串数组。例如不同的条件分支可以赋不同的硬编码值集合这些值会在编译期被转换transformed at compile-time。编译器侧的实现可以证实这一点javaScriptFocus.re 生成的_getFocusElements方法会遍历根图层的可访问元素为每个子元素构造this._elementName的引用数组再用elements.filter(Boolean)过滤掉未挂载的节点——这要求元素名称在编译期必须是确定的硬编码标识符。4.8accessibilitySelectedState动态支持平台尚未支持Not supported yet类型Boolean语义用于包含可选中元素的交互控件例如一组标签页tabs——每个标签都可聚焦focusable但任意时刻通常只有一个处于选中selected状态。Studio 数据模型中其实已经预留了对应能力Models/Accessibility.swift 的AccessibilityStates是包含disabled与selected两个 bit 的 OptionSettoData()序列化时也会写入accessibilityStates说明该能力已进入数据结构只待各平台生成器落地。4.9accessibilityDisabledState动态支持平台尚未支持Not supported yet类型Boolean语义用于当前无法交互的控件例如表单中提交按钮在必填项为空时处于禁用状态。4.10onAccessibilityActivate动态支持平台iOS 与 Web类型FunctionVoid - Void语义当元素被键盘或辅助技术激活时的回调与onPress类似通常应执行相同的逻辑。源码印证编译器在生成 Web 代码时确实为带onAccessibilityActivate的图层生成了专门的处理——javaScriptComponent.re 中的createAccessibilityWrapperComponent会用createActivatableComponent包装原图层组件生成产物命名为AccessibilityWrapperLayerName并且在 importComponents 中按是否存在可激活图层决定是否导入utils/createActivatableComponent工具。五、Swift 端的扩展方式iOS用accessLevel元数据放开原生视图当 Lona 内置参数不足以覆盖某些 iOS 无障碍需求时官方给出的路径是直接操作原生UIView在 Lona Studio 图层检查器的Metadata区域把accessLevel元数据属性从private改为public点击底部的按钮新建一行将图层的访问级别设为public生成的 Swift 代码中该图层的UIView将暴露为公开属性之后即可在代码中直接设置任何 iOS 原生无障碍属性如UIAccessibilityTraits、accessibilityFrame等。这样既保留了 Lona 生成产物的可维护性又为深度定制保留了后门。在 compiler/core/src/core/layer.re 的 metadata 结构中backingElementClass、访问级别等元数据字段共同决定了生成代码中视图的可见性与类型。macOS暂不支持文档明确说明macOS 端无障碍参数目前处于禁用状态Accessibility parameters are disabled for now。如果你需要支持 macOS 的可访问性现阶段只能通过生成的代码自行处理。六、JavaScript / Web 端的行为细节6.1 聚焦与 tabindex所有accessibilityType为element的图层在 Web 端都可以被键盘聚焦其底层 DOM 节点的tabindex被设置为-1意味着该元素只能通过编程方式或点击聚焦不能进入默认的 Tab 顺序——这正是组件内部管理 Tab 顺序这一设计的前提。源码印证javaScriptComponent.re 在生成 React DOM 代码时对可聚焦图层canBeFocused会追加tabIndex{-1} className{this.state.focusRing ? lona--focus-ring : lona--no-focus-ring} onKeyDown{this._handleKeyDown}而canBeFocused的定义见 javaScriptLayer.re图层类型为Element(_)即为可聚焦且自定义组件只要其内部任何子层可聚焦该组件整体也可聚焦递归判断。聚焦相关的ref属性needsRef也仅对 React DOM 且可聚焦的图层生成。6.2 组件的焦点管理 API组件负责管理其内部所有可聚焦 DOM 节点的 Tab 顺序与键盘事件。也就是说键盘导航的启动需要你在外部以编程方式聚焦整个组件但聚焦后组件内部哪个节点获得焦点、以及 Tab 键的流转都由组件自己处理。要聚焦组件你需要保存该组件的 Reactref。包含可访问图层的组件会暴露以下基于 ref 的方法方法行为返回值focus(options)聚焦组件内第一个可聚焦 DOM 节点有节点被聚焦返回true否则falsefocusLast(options)聚焦组件内最后一个可聚焦 DOM 节点同上focusNext(options)聚焦下一个可聚焦节点若当前焦点不在组件内则聚焦第一个若已在最后一个节点上焦点不变同上focusPrevious(options)聚焦上一个可聚焦节点若已在第一个节点上焦点不变同上每个方法都可传入一个options对象focusRing(bool)聚焦的元素是否显示轮廓。设为false时轮廓通过:focus { outline: 0; }隐藏。默认行为点击可聚焦 DOM 节点不会显示 focus ring只有键盘导航才会显示 focus ring。这些方法并非手写进每个组件而是由编译器统一生成的。在 javaScriptFocus.re 中focusMethods会把setFocusRing、isFocused、focus、focusLast、focusNext、focusPrevious、_handleKeyDown、_getFocusElements全部注入到生成组件类中。其中focus的实现L113-L139会先调用setFocusRing(options.focusRing)再调用工具函数focusFirst(this._getFocusElements())并返回布尔结果。6.3 组件级 Props焦点边界回调包含可访问图层的组件还支持以下 props用于在焦点移出组件边界时接管导航onFocusExitNext(function)当焦点位于组件内最后一个可聚焦节点且用户按下Tab时触发。回调内你可以编程方式将焦点设置到 UI 中下一个组件。该 prop 只是便利设施——若不传Tab事件会照常冒泡你可以在本组件的onKeyDownprop 或父组件中自行处理。onFocusExitPrevious(function)当焦点位于组件内第一个可聚焦节点且用户按下ShiftTab时触发。回调内可编程方式聚焦上一个组件未传时事件同样照常冒泡。源码印证javaScriptFocus.re 的_handleKeyDown完整实现了这套逻辑按下Tab时先开启 focus ring然后ShiftTab尝试focusPrevious()成功则stopPropagationpreventDefault失败已在第一个节点则若有onFocusExitPrevious则调用它并阻止事件传播否则事件冒泡Tab尝试focusNext()成功则阻止默认失败已在最后一个节点则若有onFocusExitNext则调用它并阻止传播否则冒泡最后若组件自身传了onKeyDownprop无论焦点是否被组件接管都会透传调用。6.4 React Native文档如实说明部分参数已映射到 React Native但作者尚未对整体效果做过充分测试。从编译器源码可以确认已有的映射在 javaScriptComponent.re 中对可聚焦图层canBeFocused且框架为ReactNative时会生成accessible{true}属性而removeSpecialPropsL62-L93按框架过滤了不适用的参数例如 React Native / Sketch 端会移除accessibilityRole与accessibilityCheckedSketch 端还会移除accessibilityLabel与onAccessibilityActivate——这说明参数映射是按平台裁剪的使用 React Native 生成时需自行验证实际效果。七、总结与实践建议综合文档与源码Lona 的无障碍体系可以归纳为一条清晰的链路设计时在 Lona Studio 中通过Type下拉框与Elements编辑器把顶层容器 子元素 顺序以可视化方式固化到.component文件中抽象层8 个跨平台参数parameterKey.re构成与平台无关的语义模型accessibility.re生成时编译器把语义翻译成各平台实现——Web 端生成tabindex-1、focus ring 类名、_handleKeyDown与 ref 焦点 APIjavaScriptFocus.reReact Native 端生成accessible属性iOS 端通过accessLevel元数据暴露原生视图供深度定制验证时用View Accessibility Overlay预览元素顺序与焦点位置AccessibilityOverlay.swift。实践要点回顾优先显式声明accessibilityType为none/element/container避免依赖default的平台猜测Label / Hint 走 Logic 与组件参数以支持本地化容器元素顺序用accessibilityElements显式指定可获得精确且可预览的朗读顺序Web 端键盘导航是组件自治模型——外部只需触发首次聚焦组件内部自行管理 Tab 流转并通过onFocusExitNext/onFocusExitPrevious与其他组件衔接accessibilitySelectedState、accessibilityDisabledState目前仍标记为未支持macOS 端参数同样处于禁用状态选用前需评估平台覆盖范围React Native 端映射尚属早期接入时建议进行实测验证。如需深入了解可继续阅读studio/docs/accessibility.md、Models/Accessibility.swift、Canvas/AccessibilityOverlay.swift、javaScriptFocus.re、javaScriptLayer.re、javaScriptComponent.re。赞分享设计系统前端开发工具UI组件【免费下载链接】LonaA tool for defining design systems and using them to generate cross-platform UI code, Sketch files, and other artifacts.项目地址https://gitcode.com/gh_mirrors/lo/Lona点击查看免费下载相关推荐albert accessibility支持详解无障碍设计的实践albert accessibility支持详解无障碍设计的实践 无障碍设计概述 无障碍设计Accessibility是确保所有用户包括残障人士能够有ReactXP 无障碍Accessibility开发指南跨平台屏幕阅读器支持与可访问性 API 详解ReactXP 无障碍Accessibility开发指南跨平台屏幕阅读器支持与可访问性 API 详解 ReactXP 在 iOS、Android、Web跨平台前端Gopeed accessibility支持无障碍设计的实现方法Gopeed accessibility支持无障碍设计的实现方法 引言无障碍设计在现代下载管理器中的重要性 在数字时代无障碍设计Accessibilit网络CLI后端上一篇3步解决Obsidian图片管理难题让网络图片永久本地存储下一篇从数据瓶颈到AI加速器doccano如何重构文本标注技术栈创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考