Condividi tramite


Accessibilità tramite tastiera

L'accessibilità tramite tastiera deve essere considerata come un modello di interazione principale, non come fallback secondario. Un'esperienza di tastiera affidabile supporta gli utenti con diverse disabilità e limitazioni (tra cui visione, apprendimento, dexterity/mobilità e disabilità di linguaggio/comunicazione). Migliora anche la produttività per gli utenti che preferiscono l'interazione da tastiera per velocità e precisione.

Se l'accesso tramite tastiera è incompleto o incoerente, gli utenti possono perdere l'accesso alla funzionalità principale dell'app anche quando l'interazione del puntatore appare completamente implementata.

Spostamento tramite tastiera tra gli elementi dell'interfaccia utente

Per interagire con un controllo tramite la tastiera, i controlli devono essere focalizzabili e raggiungibili tramite navigazione tramite focus. Per ricevere lo stato attivo (senza usare un puntatore), il controllo deve essere accessibile tramite la navigazione tramite tabulazione. Per impostazione predefinita, l'ordine di tabulazione dei controlli corrisponde all'ordine in cui vengono aggiunti a una superficie di progettazione, dichiarato in XAML o aggiunti programmando a un contenitore.

In molte interfacce utente, questo comportamento predefinito è accettabile e allineato al flusso di lettura. Tuttavia, l'ordine visivo e l'ordine della tastiera possono variare a seconda del layout del contenitore e del posizionamento figlio. Questa divergenza deve essere intenzionale e testata.

Convalidare il comportamento della scheda in modo esplicito. Griglia, tabella e layout simili sono origini comuni di mancata corrispondenza tra l'ordine di lettura percepito e l'ordine di messa a fuoco. Testare entrambi i percorsi di interazione tramite tastiera e tocco per garantire che l'attraversamento rimanga efficiente e prevedibile.

Per allineare l'attraversamento al flusso visivo, puoi ristrutturare XAML o assegnare in modo esplicito TabIndex. Nell'esempio seguente si utilizza una griglia con sequenza di tabulazione con ordine prioritario per la prima colonna.

<Grid>
  <Grid.RowDefinitions>...</Grid.RowDefinitions>
  <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>

  <TextBlock Grid.Column="1" HorizontalAlignment="Center">Groom</TextBlock>
  <TextBlock Grid.Column="2" HorizontalAlignment="Center">Bride</TextBlock>

  <TextBlock Grid.Row="1">First name</TextBlock>
  <TextBox x:Name="GroomFirstName" Grid.Row="1" Grid.Column="1" TabIndex="1"/>
  <TextBox x:Name="BrideFirstName" Grid.Row="1" Grid.Column="2" TabIndex="3"/>

  <TextBlock Grid.Row="2">Last name</TextBlock>
  <TextBox x:Name="GroomLastName" Grid.Row="2" Grid.Column="1" TabIndex="2"/>
  <TextBox x:Name="BrideLastName" Grid.Row="2" Grid.Column="2" TabIndex="4"/>
</Grid>

In alcuni scenari, un elemento deve essere escluso dall'attraversamento tramite tabulazione. L'approccio standard consiste nell'impostare IsEnabled su false, che disabilita anche l'interazione. I controlli disabilitati vengono rimossi automaticamente dalla sequenza di tabulazione.

Se un elemento rimane interattivo tramite altri meccanismi, ma non deve essere raggiunto con Tab, impostare IsTabStop su false.

La maggior parte dei controlli focalizzabili è inclusa nell'ordine di tabulazione per impostazione predefinita. Un'eccezione comune è costituita dai controlli di visualizzazione del testo, come RichTextBlock, che possono supportare lo stato focus per la selezione del testo e le operazioni con gli appunti (clipboard), ma in genere non sono tabulazioni perché non sono controlli attivabili tramite comandi. Questi controlli possono comunque essere individuati tramite tecnologie assistive attraverso la semantica dell'automazione, ad esempio il modello di controllo Text.

Indipendentemente dal fatto che si usi l'attraversamento predefinito o tabIndex esplicito, si applicano le regole seguenti:

  • Se TabIndex non è impostato su un elemento, il valore predefinito è Int32.MaxValue e l'ordine è basato sull'ordine di dichiarazione/inserimento.
  • Se TabIndex è impostato su un elemento:
    • Gli elementi con TabIndex uguale a 0 vengono aggiunti in base all'ordine di dichiarazione/inserimento.
    • Gli elementi con TabIndex maggiore di 0 vengono aggiunti in ordine crescente di TabIndex .
    • Gli elementi con TabIndex minore di 0 vengono aggiunti prima degli elementi con valori zero.

Il frammento di codice seguente mostra le impostazioni di TabIndex miste (B usa Int32.MaxValue o 2.147.483.647).

<StackPanel Background="#333">
  <StackPanel Background="#FF33FF">
    <Button>A</Button>
    <Button TabIndex="2147483647">B</Button>
    <Button>C</Button>
  </StackPanel>
  <StackPanel Background="#33FFFF">
    <Button TabIndex="1">D</Button>
    <Button TabIndex="1">E</Button>
    <Button TabIndex="0">F</Button>
  </StackPanel>
</StackPanel>

In questo modo viene generato l'ordine di tabulazioni seguente:

  1. F
  2. D
  3. E
  4. Un
  5. B
  6. C

Spostamento tramite tastiera tra i riquadri dell'applicazione con F6

Un riquadro applicazione è un'area attività prominente all'interno di una finestra. In Microsoft Edge, ad esempio, i riquadri includono la barra degli indirizzi, la barra dei segnalibri, la barra delle schede e l'area del contenuto. F6 viene comunemente usato per spostare il focus tra questi riquadri, con elementi figlio accessibili tramite la navigazione standard da tastiera.

Anche se un modello di spostamento da tastiera conforme è la linea di base, un modello di spostamento tramite tastiera utilizzabile include in genere:

  • Ascoltare F6 per spostarsi tra le aree principali dell'interfaccia utente.
  • Fornire tasti di scelta rapida per i comandi ad alta frequenza.
  • Fornire chiavi di accesso per controlli importanti.

Per indicazioni sull'implementazione, vedere Tasti di scelta rapida e Tasti di accesso rapido.

Ottimizzare per F6

F6 riduce significativamente i costi di navigazione consentendo agli utenti di muoversi tra le aree principali anziché passare in rassegna ogni controllo figlio.

Ad esempio, F6 in Microsoft Edge scorre tra la barra degli indirizzi, la barra dei segnalibri, la barra delle schede e il contenuto. Poiché una pagina può contenere molte tabulazioni, ciò rende le attività di navigazione comuni molto più efficienti.

La sequenza F6 può essere allineata con punti di riferimento o intestazioni, ma non deve corrispondere esattamente. Usare F6 per lo spostamento in ampie aree e punti di riferimento/intestazioni per la struttura semantica all'interno e tra le regioni.

Importante

Devi implementare lo spostamento F6 in modo esplicito nella tua app; non viene fornito automaticamente.

Se possibile, ogni area di destinazione F6 deve avere un nome accessibile chiaro, dalla semantica dei punti di riferimento o impostando AutomationProperties.Name nella radice dell'area.

MAIUSC+F6 deve attraversare lo stesso ciclo in ordine inverso.

Spostamento tramite tastiera all'interno di un elemento dell'interfaccia utente

I controlli compositi devono fornire una navigazione interna prevedibile tra gli elementi figlio. Un modello comune consiste nel mantenere la radice composita nell'ordine di navigazione tramite tabulazione e gestire internamente i discendenti attivi, anziché esporre ogni figlio come fermata separata della tabulazione.

Molti controlli predefiniti implementano già questo comportamento. Ad esempio, l'attraversamento con tasti di direzione è disponibile per impostazione predefinita per ListView, GridView, ListBox e FlipView.

Alternative della tastiera alle azioni e agli eventi del puntatore per elementi di controllo specifici

Qualsiasi interfaccia utente che può essere attivata dal puntatore deve essere richiamata anche dalla tastiera. L'attivazione richiede che l'elemento abbia lo stato attivo (solo le classi che derivano da Controllo supportano lo stato attivo e la navigazione tramite tabulazione).

Per i controlli che possono essere richiamati, implementare i gestori eventi della tastiera per la barra spaziatrice e i tasti Invio. Ciò garantisce la parità di tastiera di base con le interazioni del puntatore.

Se un elemento non è focalizzabile per impostazione predefinita, usa un tipo di controllo focalizzabile o implementa un controllo personalizzato con una gestione del focus esplicita. In tal caso, impostare IsTabStop su true e fornire un indicatore di focus visibile.

In molti casi, la composizione è più semplice e più affidabile rispetto al comportamento personalizzato di solo puntatore. Ad esempio, invece di gestire l'input del puntatore direttamente in un'immagine, posizionarlo all'interno di un pulsante per ereditare l'attivazione della tastiera, la gestione dello stato attivo e il comportamento di automazione.

<!--Don't do this.-->
<Image Source="sample.jpg" PointerPressed="Image_PointerPressed"/>

<!--Do this instead.-->
<Button Click="Button_Click"
        AutomationProperties.Name="Open profile photo">
  <Image Source="Assets/profile-photo.png"/>
</Button>

Scelte rapide da tastiera

Oltre alla navigazione e all'attivazione, implementare una scorciatoia (una combinazione di tasti che fornisce un accesso efficiente alle funzionalità dell'app) per comandi importanti o frequentemente utilizzati con tasti di scelta rapida e tasti di accesso.

Due tipi comuni di collegamento sono:

  • Acceleratori: richiamare i comandi direttamente, con o senza un controllo visibile corrispondente.
  • Tasti di accesso: consentono di spostare l'attenzione su controlli specifici nell'interfaccia utente.

Rendere sempre individuabili le scorciatoie per gli utenti di tecnologia assistiva. Comunicarli tramite descrizioni comandi, metadati di automazione, elementi dell'interfaccia utente visibili e documentazione di supporto.

Per esporre i metadati delle scorciatoie alle tecnologie assistive, usare AutomationProperties.AccessKey per le scorciatoie mnemonici e AutomationProperties.AcceleratorKey per le scorciatoie da tastiera per comandi. Poiché i lettori di schermo possono presentare questi tasti di scelta rapida in modo simile, documenta i tasti di scelta rapida attraverso più canali.

Nell'esempio seguente viene illustrato come documentare i tasti di scelta rapida per i pulsanti di riproduzione multimediale, sospensione e arresto.

<Grid>

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaPlayerElement x:Name="DemoPlayer"
    Width="500" Height="300" Margin="20"
    HorizontalAlignment="Center"
    AutoPlay="False"
    AreTransportControlsEnabled="True" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Ctrl+P"
      AutomationProperties.AccessKey="Alt+P">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="P"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Ctrl+A"
      AutomationProperties.AccessKey="Alt+A">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="A"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Ctrl+S"
      AutomationProperties.AccessKey="Alt+S">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="S"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Stop</TextBlock>
    </Button>
  </StackPanel>
</Grid>

Importante

L'impostazione di AutomationProperties.AcceleratorKey o AutomationProperties.AccessKey non implementa il comportamento della tastiera. Queste proprietà espongono i metadati all'Automazione dell'interfaccia utente in modo che le tecnologie assistive possano annunciare le scorciatoie previste.

Il comportamento della tastiera deve essere ancora implementato nel codice. Usare le definizioni dichiarative KeyboardAccelerator quando possibile e usare i gestori KeyDown o KeyUp in cui è necessaria la logica di routing personalizzata. Si noti anche che lo stile della sottolineatura della chiave di accesso non è automatico. Per desiderare sottolineature mnemoniche visibili, eseguirne il rendering in modo esplicito (ad esempio, con sottolineatura).

Per brevità, l'esempio omette le risorse stringa, ad esempio "CTRL+A". Nell'ambiente di produzione, localizzare il testo dei collegamenti rapidi e convalidare le scelte mnemoniche per contesto locale, poiché la selezione dei tasti dipende spesso dalle etichette tradotte.

Per altre indicazioni, vedere Tasti di scelta rapida nelle Linee guida per l'interazione dell'esperienza utente di Windows.

Implementazione di un gestore di eventi chiave

L'input da tastiera usa eventi indirizzati. Gli eventi indirizzati possono propagarsi da elementi figlio a un contenitore padre, consentendo al contenitore padre di elaborare le scorciatoie per più elementi discendenti. Questo modello di evento è utile per definire le azioni dei tasti di scelta rapida per un controllo che contiene diversi sotto-elementi, nessuno dei quali può avere lo stato attivo o far parte del tabulatore.

Per esempi di codice che includono controlli dei tasti di modifica ,ad esempio CTRL, vedi Interazioni da tastiera.

Spostamento tramite tastiera per i controlli personalizzati

Per i controlli personalizzati, usare i tasti di direzione quando gli elementi figlio sono correlati nello spazio. Negli scenari ad albero in cui l'espansione/compressione e l'attivazione sono interazioni separate, mappare le frecce sinistra e destra per espandere/comprimere il comportamento. Per i controlli orientati, associare i tasti direzionali all'orientamento visivo del controllo.

Il comportamento della chiave personalizzata viene comunemente implementato eseguendo l'override di OnKeyDown e OnKeyUp.

Esempio di stato visivo per un indicatore di messa a fuoco

Qualsiasi controllo personalizzato con messa a fuoco deve esporre un indicatore visivo chiaro. Un modello comune usa una sovrimpressione Rectangle che inizia nascosta tramite Visibilità e viene visualizzata quando riceve il focus.

I controlli XAML predefiniti forniscono già indicatori di stato attivo. L'aspetto esatto può variare con le impostazioni del tema, inclusa la modalità a contrasto elevato. Se si riprogetta il template dei controlli, mantenere un comportamento di visibilità dello stato attivo equivalente.

L'esempio seguente viene adattato dal modello Button predefinito.

<ControlTemplate TargetType="Button">
...
    <Rectangle
      x:Name="FocusVisualWhite"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="1.5"/>
    <Rectangle
      x:Name="FocusVisualBlack"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="0.5"/>
...
</ControlTemplate>

Per attivare o disattivare la visibilità dell'indicatore di stato attivo, usare VisualStateManager e VisualStateManager.VisualStateGroups nella radice del modello.

<ControlTemplate TargetType="Button">
  <Grid>
    <VisualStateManager.VisualStateGroups>
      <!--other visual state groups here-->
      <VisualStateGroup x:Name="FocusStates">
        <VisualState x:Name="Focused">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="FocusVisualWhite"
              Storyboard.TargetProperty="Opacity"
              To="1" Duration="0"/>
            <DoubleAnimation
              Storyboard.TargetName="FocusVisualBlack"
              Storyboard.TargetProperty="Opacity"
              To="1" Duration="0"/>
          </Storyboard>
        </VisualState>
        <VisualState x:Name="Unfocused" />
        <VisualState x:Name="PointerFocused" />
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!--composition is here-->
  </Grid>
</ControlTemplate>

Solo uno stato in questo gruppo modifica esplicitamente la visualizzazione del focus. Gli altri stati possono rimanere vuoti perché le transizioni all'interno dello stesso Oggetto VisualStateGroup annullano le animazioni di stato precedenti. Gli eventi di stato attivo, ad esempio GotFocus, combinati con GoToState, in genere determinano queste transizioni.

Accessibilità tramite tastiera e dispositivi senza una tastiera hardware

Alcuni dispositivi si basano su un pannello SIP (Soft Input Panel) anziché su una tastiera hardware. Le utilità per la lettura dello schermo possono rilevare che l'utente sta scansionando i tasti e annunciare l'esplorazione dei tasti SIP di un utente, e molti concetti di accessibilità della tastiera vengono ancora applicati tramite equivalenti gestuali.

Ad esempio, anche senza un tasto Tab fisico, Narratore supporta gesti che simulano l'attraversamento come il tasto Tab. Ciò significa che l'ordine di tabulazioni coerente è ancora critico. L'Assistente vocale fornisce anche equivalenti dei gesti per la navigazione direzionale in controlli complessi (vedere Comandi della tastiera e gesti touch dell'Assistente vocale).

Esempi

Icona della raccolta WinUI 3 L'app Raccolta WinUI 3 include esempi interattivi di controlli e funzionalità WinUI. Ottenere l'app dal Microsoft Store o esplorare il codice sorgente in GitHub.