Acción inaccesible
Asegúrate de que los elementos interactivos se puedan activar con VoiceOver
Esta es una regla experimental, y por lo tanto, su(s) resultado(s) se consideran en fase beta. Aprende más acerca de reglas experimentales y cómo puedes ayudar a mejorarlas.
Qué Verificamos
Un elemento interactivo debe ser activable por tecnología asistiva. Esta regla verifica que la acción asociada con un elemento interactivo puede enfocarse y y activarse usando VoiceOver.
Ejemplo de Fallo ❌
VoiceOver puede focus el interruptor de 'Notificaciones' pero cannot activate it
VoiceOver anuncia "Notifications, on." - no se proporciona rol ni pista de activación
El doble toque no hace nada; los usuarios no tienen manera de cambiar la configuración
Ejemplo de Éxito ✅
VoiceOver puede focus and activate el interruptor de 'Notificaciones'
VoiceOver anuncia "Notifications, switch button, on. Double-tap to activate."
El rol y la pista de activación están presentes; los usuarios saben exactamente cómo interactuar con el control
En Resumen
- Esta regla tiene un impacto crítico para los usuarios
- Esta regla marca elementos interactivos en los que VoiceOver no puede enfocarse o activar
- Esto ocurre cuando un elemento no es enfocable en sí mismo y no está dentro de un padre enfocable
- Un elemento interactivo que está dentro de un padre enfocable es inaccesible cuando no se detecta ninguna acción, reconocedor de gestos, o punto de activación
Impacto para los Usuarios
Los usuarios de tecnología asistiva son los más impactados. Cuando VoiceOver puede enfocarse en un elemento interactivo pero no puede activarlo, los usuarios pueden ser incapaces de completar acciones críticas - como enviar un formulario, cambiar una configuración o navegar a otra pantalla. Esto crea una barrera completa para las personas que dependen exclusivamente de VoiceOver para interactuar con la aplicación.
Confirmar Problema de Acción Inaccesible
- Activa VoiceOver
- Enfoca el elemento
- Sucederá una de las siguientes cosas:
- Inaccesible: El usuario no podrá activar el elemento usando VoiceOver
- Accesible: El usuario podrá usar VoiceOver para activar el elemento
Solucionar Problemas
Existen varios escenarios que pueden resultar en un problema de Acción Inaccesible. La solución depende de cómo está estructurado el elemento. Revisa los enfoques a continuación y utiliza el que corresponda a tu diseño.
UIKit
Hay varios enfoques, dependiendo de cómo esté estructurado el elemento.
Solución en Storyboard — asegura que el control activo sea un elemento accesible:
- Selecciona el elemento con un problema de
InaccessibleAction. - Asegúrate de que el Panel de Inspectores esté visible.
- Selecciona el Inspector de Identidad.
- En Accesibilidad, asegúrate de que la casilla "Habilitado" esté seleccionada para el control activo.
Una opción alternativa es cambiar la ruta de accesibilidad del elemento:
- Repite los pasos 1–3 para el control activo, su etiqueta y el elemento contenedor.
- Asegúrate de que la casilla "Habilitado" esté seleccionada solo para el control activo, no para la etiqueta o el elemento contenedor.
- En el código, actualiza la ruta de accesibilidad para incluir tanto la etiqueta como el control activo (consulta la solución de ruta de accesibilidad en código a continuación).
Otra solución es centrar el control activo dentro de su padre para que el punto de activación predeterminado de VoiceOver pueda alcanzarlo:
- Selecciona el elemento con un problema de
InaccessibleAction. - Asegúrate de que el Panel de Inspectores esté visible.
- Selecciona el control activo.
- Seleccione el Inspector de Tamaño.
- Asegúrese de que el control activo esté centrado horizontal y verticalmente dentro de su elemento contenedor.
Corregir en el código:
Asegúrese de que el isAccessibilityElement del control activo esté configurado en true:
buttonContainerView.isAccessibilityElement = trueAñada un reconocedor de gestos de toque a la vista contenedora:
buttonContainerView.addGestureRecognizer(UITapGestureRecognizer(target: self, selector: #selector(buttonTapped)))Centre el control activo dentro de la vista principal para que el accessibilityActivationPoint de VoiceOver active su acción:
buttonContainerView.button.centerXAnchor.constraint(equalTo: buttonContainerView.centerXAnchor).isActive = true
buttonContainerView.button.centerYAnchor.constraint(equalTo: buttonContainerView.centerYAnchor).isActive = trueActualice la ruta de accesibilidad para incluir tanto la etiqueta como el control activo.
Configure isAccessibilityElement=false en la etiqueta y en el elemento padre, de manera que solo el control en sí (el toggle, en este caso) sea un elemento de accesibilidad.
// 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
Este problema no ocurrirá en la mayoría de los elementos y controles predeterminados en SwiftUI, pero puede ocurrir con controles personalizados o cuando los elementos están agrupados incorrectamente.
Al construir controles personalizados que imiten el comportamiento de un selector, deslizador o interruptor, use .accessibilityRepresentation para dar al control personalizado el mismo comportamiento de accesibilidad que su equivalente estándar:
// 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)")
})
}Al agrupar vistas juntas, use .accessibilityElement(children: .combine) o .accessibilityElement(children: .contain) para asegurar que todas las acciones en los controles secundarios sigan siendo accesibles:
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"))Si la vista contenedora tiene un control ajustable como un selector o deslizador, use .accessibilityAdjustableAction para proporcionar la mejor experiencia de accesibilidad:
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
Este problema es poco común para los controles estándar tocables o pulsables en React Native, pero puede ocurrir con controles personalizados.
Opción 1: Permitir que la vista principal maneje el enfoque
Establezca la propiedad accessible de la vista contenedora en true y accessibilityElementsHidden en false, y asigne el accessibilityRole adecuado:
<View
accessible={true}
accessibilityElementsHidden={false}
accessibilityRole='link'
accessibilityLabel='Learn more about Deque'
onTouchStart={openLink}
>
<Image
source={DequeLogo}
style={{ width: 100, height: 100 }}
/>
</View>Opción 2: Permitir que el elemento en sí mismo maneje el enfoque
Configure accessible, accessibilityElementsHidden y accessibilityRole directamente en el control:
<Image
source={DequeLogo}
accessible={true}
accessibilityElementsHidden={false}
accessibilityRole='link'
accessibilityLabel='Learn more about Deque'
onTouchStart={openLink}
style={{ width: 100, height: 100 }}
/>Flutter
Los widgets de Material de Flutter (ElevatedButton, IconButton, etc.) exponen acciones de toque al lector de pantalla automáticamente. Al construir elementos interactivos personalizados con GestureDetector, envuélvalos en MergeSemantics con un widget Semantics para asegurarse de que el lector de pantalla pueda descubrir y activar el elemento en una sola parada de enfoque.
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'),
),
),
),
)¿Puedo ignorar esta regla?
La Acción Inaccesible tiene un impacto crítico para los usuarios, y recomendamos encarecidamente corregir estos problemas. Dado que esta es una regla experimental, debería verificar los resultados manualmente. Si ha confirmado que el elemento es activable por VoiceOver, puede ser aceptable ignorar el hallazgo. Más información sobre ignorando reglas.
Recursos
Páginas de Cursos de Deque University
Nota: El acceso completo a los recursos de Deque University requiere una suscripción.
Otros Recursos
- Pautas de Accesibilidad para el Contenido Web (WCAG) 2.1, Recomendación del W3C
- Documentos de Comprensión de WCAG 2.1
