跳到主內容

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.'),
            ),
          ),
        ],
      ),
    );
  }
}