跳到主内容

Web 辅助功能

有关 Web 无障碍访问的信息

背景

#

Flutter 通过将其内部语义树(Semantics tree)转换为屏幕阅读器可理解的 HTML DOM 结构来支持 Web 无障碍访问。由于 Flutter 在单个画布(canvas)上渲染 UI,因此需要一个特殊的层将 UI 的含义和结构暴露给 Web 浏览器。

选择性启用 Web 无障碍访问

#

隐藏按钮

#

出于性能考虑,Flutter 的 Web 无障碍访问功能默认处于关闭状态。若要开启无障碍访问,用户需要点击一个带有 aria-label="Enable accessibility" 的隐藏按钮。点击该按钮后,DOM 树将反映出所有组件(widgets)的无障碍信息。

在代码中开启无障碍模式

#

另一种方法是在运行应用时通过添加以下代码来开启无障碍模式。

dart
import 'package:flutter/semantics.dart';

void main() {
  runApp(const MyApp());
  if (kIsWeb) {
    SemanticsBinding.instance.ensureSemantics();
  }
}

通过语义角色增强无障碍性

#

什么是语义角色?

#

语义角色定义了 UI 元素的目的,有助于屏幕阅读器和其他辅助技术向用户有效解释并呈现您的应用。例如,角色可以指示某个组件是按钮、链接、标题、滑块还是表格的一部分。

虽然 Flutter 的标准组件通常会自动提供这些语义,但如果自定义组件没有明确定义的角色,屏幕阅读器用户可能无法理解它。

通过分配适当的角色,您可以确保:

  • 屏幕阅读器能够正确播报元素的类型和用途。
  • 用户能够使用辅助技术更有效地浏览您的应用。
  • 您的应用符合 Web 无障碍访问标准,从而提升可用性。

在 Flutter Web 中使用 SemanticsRole

#

Flutter 提供了带有 SemanticsRole 枚举Semantics 组件,允许开发者为组件分配特定的角色。当您的 Flutter Web 应用进行渲染时,这些 Flutter 特有的角色会被转换为网页 HTML 结构中相应的 ARIA 角色。

1. 来自标准组件的自动语义

许多标准 Flutter 组件(如 TabBarMenuAnchorTable)会自动包含语义信息及其角色。请尽可能优先使用这些标准组件,因为它们开箱即用地处理了许多无障碍访问方面的问题。

2. 显式添加或覆盖角色

对于自定义组件,或者当默认语义不足以满足需求时,请使用 Semantics 组件来定义角色。

以下是如何显式定义列表及其条目的示例:

dart
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';


class MyCustomListWidget extends StatelessWidget {
  const MyCustomListWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // This example shows how to explicitly assign list and listitem roles
    // when building a custom list structure.
    return Semantics(
      role: SemanticsRole.list,
      explicitChildNodes: true,
      child: Column(
        children: <Widget>[
          Semantics(
            role: SemanticsRole.listItem,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the first custom list item.'),
            ),
          ),
          Semantics(
            role: SemanticsRole.listItem,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the second custom list item.'),
            ),
          ),
        ],
      ),
    );
  }
}