Ação Inacessível

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard

Assegure que elementos interativos possam ser ativados com o VoiceOver

Not for use with personal data
note

Esta é uma regra experimental e, portanto, seus resultados são considerados em fase de testes beta. Saiba mais sobre regras experimentais e como você pode ajudar a melhorá-las.

WCAG 2.0 - 2.1.1 A Impact - Critical

O que Verificamos

Um elemento interativo deve ser ativável por tecnologia assistiva. Esta regra verifica se a ação associada a um elemento interativo pode ser focada e acionada usando o VoiceOver.

Visão Geral

  • Esta regra tem um impacto crítico para os usuários
  • Esta regra sinaliza elementos interativos nos quais o VoiceOver não pode focar ou ativar
  • Isso acontece quando um elemento não é focável por si só e não está dentro de um elemento pai focável
  • Um elemento interativo que está dentro de um elemento pai focável é inacessível quando nenhuma ação, reconhecedor de gestos ou ponto de ativação é detectado

Impacto para os Usuários

Usuários de tecnologia assistiva são os mais impactados. Quando o VoiceOver pode focar em um elemento interativo, mas não pode ativá-lo, os usuários podem ficar impossibilitados de completar ações críticas - como enviar um formulário, alternar uma configuração ou navegar para outra tela. Isso cria uma barreira completa para pessoas que dependem exclusivamente do VoiceOver para interagir com o aplicativo.

Confirmar Problema de Ação Inacessível

  1. Ligue o VoiceOver
  2. Foque no elemento
  3. Uma das seguintes situações ocorrerá:
    • Inacessível: O usuário não conseguirá ativar o elemento usando o VoiceOver
    • Acessível: O usuário conseguirá usar o VoiceOver para ativar o elemento

Corrigir Problemas

Existem vários cenários que podem resultar em um problema de Ação Inacessível. A correção depende de como o elemento está estruturado. Revise as abordagens abaixo e use aquela que corresponde ao seu layout.

UIKit

Existem várias abordagens, dependendo de como o elemento está estruturado.

Correção no Storyboard — certifique-se de que o controle ativo é um elemento de acessibilidade:

  1. Selecione o elemento com um InaccessibleAction problema.
  2. Certifique-se de que o Painel de Inspetores esteja visível.
  3. Selecione o Inspetor de Identidade.
  4. Em Acessibilidade, assegure-se de que a caixa "Habilitado" esteja selecionada para o controle ativo.

Uma opção alternativa é alterar o caminho de acessibilidade do elemento:

  1. Repita os passos 1–3 para o controle ativo, seu rótulo, e o elemento que o contém.
  2. Assegure-se de que a caixa "Habilitado" esteja selecionada apenas para o controle ativo, não para o rótulo ou o elemento que o contém.
  3. No código, atualize o caminho de acessibilidade para incluir tanto o rótulo quanto o controle ativo (veja a correção de caminho de acessibilidade no código abaixo).

Outra solução é centralizar o controle ativo dentro de seu elemento pai para que o ponto de ativação padrão do VoiceOver possa alcançá-lo:

  1. Selecione o elemento com um InaccessibleAction problema.
  2. Certifique-se de que o Painel de Inspetores esteja visível.
  3. Selecione o controle ativo.
  4. Selecione o Inspetor de Tamanho.
  5. Certifique-se de que o controle ativo esteja centralizado horizontalmente e verticalmente dentro do seu elemento pai.

Correção no código:

Verifique se o controle ativo isAccessibilityElement está configurado para true:

buttonContainerView.isAccessibilityElement = true

Adicione um reconhecedor de gestos de toque à vista que o contém:

buttonContainerView.addGestureRecognizer(UITapGestureRecognizer(target: self, selector: #selector(buttonTapped)))

Centralize o controle ativo dentro da vista principal para que o VoiceOver accessibilityActivationPoint dispare sua ação:

buttonContainerView.button.centerXAnchor.constraint(equalTo: buttonContainerView.centerXAnchor).isActive = true
buttonContainerView.button.centerYAnchor.constraint(equalTo: buttonContainerView.centerYAnchor).isActive = true

Atualize o caminho de acessibilidade para incluir tanto o rótulo quanto o controle ativo.

Defina isAccessibilityElement=false no rótulo e no elemento pai, para que apenas o próprio controle (o toggle, neste caso) seja um elemento de acessibilidade.

// 1. Only the toggle should be an accessibility element
toggleContainerView.toggle.isAccessibilityElement = true
toggleContainerView.label.isAccessibilityElement = false
toggleContainerView.isAccessibilityElement = false

// 2. Expand the toggle's accessibilityPath to encompass the full container
// so VoiceOver's focus ring covers both the label and the toggle
let containerFrame = toggleContainerView.superview!.convert(toggleContainerView.frame, to: toggleContainerView.superview)
toggleContainerView.toggle.accessibilityPath = UIBezierPath(rect: containerFrame)

SwiftUI

Esse problema não ocorrerá na maioria dos elementos e controles padrão no SwiftUI, mas pode ocorrer com controles personalizados ou quando elementos são agrupados incorretamente.

Ao construir controles personalizados que imitam o comportamento de um stepper, slider ou toggle, use .accessibilityRepresentation para dar ao controle personalizado o mesmo comportamento de acessibilidade do seu equivalente padrão:

// Add .accessibilityRepresentation on a custom Toggle view
HStack {
    Text("Dark mode is \(getDarkModeStatus().localized)")
    Image(systemName: getDarkModeImage())
}.onTapGesture {
    isOn.toggle()
}
.accessibilityRepresentation {
    Toggle(isOn: $isOn, label: {
        Text("Dark mode is \(getDarkModeStatus().localized)")
    })
}

Ao agrupar vistas, use .accessibilityElement(children: .combine) ou .accessibilityElement(children: .contain) para garantir que todas as ações nos controles filhos permaneçam acessíveis:

VStack(alignment: .leading) {
    Text("Adjust settings below")
        .accessibilityElement(children: .ignore)
    Divider()
    Toggle(isOn: $isOn) {
        Text("Dark Mode is \(toggleStateText())")
    }
    .accessibility(value: Text("Dark Mode is \(toggleStateText())"))
}
.accessibilityElement(children: .combine)
.accessibilityLabel(Text("Adjust settings below"))

Se a vista que o contém tiver um controle ajustável como um stepper ou slider, use .accessibilityAdjustableAction para proporcionar a melhor experiência de acessibilidade:

VStack {
    Text("Adjust the stepper below to update dog petting data".localized)
    Divider()
    HStack {
        Stepper(value: $value) {
            Text("Total dogs pet today \($value.wrappedValue)")
        }.accessibilityElement(children: .ignore)
    }
}
.accessibilityElement(children: .combine)
.accessibilityValue(Text("\($value.wrappedValue)"))
.accessibilityAdjustableAction({ direction in
    switch direction {
    case .increment:
        value += 1
    case .decrement:
        value -= 1
    @unknown default:
        print("unknown direction used")
    }
})

React Native

Esse problema é incomum para controles tocáveis ou pressionáveis padrão no React Native, mas pode ocorrer com controles personalizados.

Opção 1: Permitir que a vista pai gerencie o foco

Defina a propriedade da vista que o contém accessible para true e accessibilityElementsHidden para false, e atribua o(a) accessibilityRoleapropriado:

<View
  accessible={true}
  accessibilityElementsHidden={false}
  accessibilityRole='link'
  accessibilityLabel='Learn more about Deque'
  onTouchStart={openLink}
>
  <Image 
    source={DequeLogo}
    style={{ width: 100, height: 100 }} 
  />
</View>

Opção 2: Permitir que o próprio elemento gerencie o foco

Defina accessible, accessibilityElementsHidden, e accessibilityRole diretamente no controle:

<Image
  source={DequeLogo}
  accessible={true}
  accessibilityElementsHidden={false}
  accessibilityRole='link'
  accessibilityLabel='Learn more about Deque'
  onTouchStart={openLink}
  style={{ width: 100, height: 100 }}
/>

Flutter

Os widgets Material do Flutter (ElevatedButton, IconButton, etc.) expõem ações de toque ao leitor de tela automaticamente. Ao construir elementos interativos personalizados com GestureDetector, envolva-os com MergeSemantics com um widget Semantics para garantir que o leitor de tela possa descobrir e ativar o elemento em uma única parada de foco.

MergeSemantics(
  child: Semantics(
    button: true,
    label: 'Archive item',
    child: GestureDetector(
      onTap: () {},
      child: Container(
        padding: const EdgeInsets.all(12.0),
        color: Colors.green.shade100,
        child: const Text('Archive item'),
      ),
    ),
  ),
)

Posso ignorar esta regra?

A ação inacessível tem um impacto crítico para os usuários, e recomendamos fortemente a correção desses problemas. Como esta é uma regra experimental, você deve verificar os resultados manualmente. Se você confirmou que o elemento pode ser ativado pelo VoiceOver, pode ser aceitável ignorar o aviso. Saiba mais sobre ignorar regras.

Recursos

Páginas do Curso Deque University

Nota: O acesso completo aos recursos da Deque University requer uma assinatura.

Outros Recursos