Verschachteltes fokussierbares Element
Fokussierbare Elemente sollten nicht innerhalb von klickbaren übergeordneten Elementen verschachtelt sein, da sie ihre Rolle gegenüber Hilfstechnologien wie TalkBack und Voice Access nicht korrekt mitteilen.
Über diese Regel
Die Regel für verschachtelte fokussierbare Elemente überprüft alle fokussierbaren Steuerelemente, die nicht interaktiv sind. Wenn sich ein solches Steuerelement innerhalb eines klickbaren übergeordneten Elements befindet, wird es dadurch interaktiv, gibt jedoch keine Rolle bekannt. Daher wird dieses Element als Barrierefreiheitsproblem gekennzeichnet.
Auswirkungen auf Benutzer
Wenn Assistenztechnologien keine Rolle ankündigen, wissen blinde oder sehbehinderte Nutzer, die auf Assistenztechnologien wie TalkBack angewiesen sind, nicht, dass sie eine Aktion auslösen können. TalkBack konzentriert sich beispielsweise auf ein inneres Element und liest dessen Text „Starte einen Toast“ vor – und sonst nichts. Es wird nicht angesagt, dass es sich um eine Schaltfläche handelt oder dass der Benutzer das Element doppelt tippen muss, um es zu aktivieren.
Bestätigung
- Aktivieren Sie TalkBack / das Bildschirmleseprogramm.
- Setzen Sie den Fokus auf die Ansicht und alle ihre untergeordneten Elemente.
- Eines der folgenden Ereignisse wird eintreten:
- Nicht barrierefrei: TalkBack liest den Text vor, nennt aber weder eine Rolle noch eine Interaktionsmöglichkeit.
- Barrierefrei: TalkBack liest den gesamten Text vor. TalkBack gibt außerdem eine Rolle und/oder Hinweise zur Interaktion mit dem Element aus.
So beheben Sie das Problem
Verschachteln Sie kein fokussierbares, nicht interaktives Steuerelement innerhalb eines anklickbaren übergeordneten Steuerelements. Stellen Sie sicher, dass dem verschachtelten Steuerelement keine Eigenschaften zugewiesen sind, die es fokussierbar machen würden. So kann das interaktive übergeordnete Element den Fokus erhalten und seine Rolle bekanntgeben. Konkrete Beispiele finden Sie unten.
Um ein falsch-positives Accessibility-Ergebnis zu vermeiden, stellen Sie sicher, dass Container-Views, die beim Antippen keine Aktion auslösen, nicht als anklickbar festgelegt sind. Unsere Tools können nicht feststellen, ob eine anklickbare Ansicht mit einer programmierten Aktion verknüpft ist, daher müssen wir davon ausgehen, dass dies der Fall ist, um potenziell nicht barrierefreies Verhalten zu melden.
Überprüfen Sie die umgebenden Containeransichten – wie Frame Layouts, Card Views oder Drawers –, um sicherzustellen, dass jede Ansicht, die keine Aktion zugeordnet bekommen soll, nicht als anklickbar festgelegt ist.
XML
Nicht bestandenes Beispiel
In diesem Beispiel ist das MaterialCardView anklickbar, aber das untergeordnete LinearLayout erhält stattdessen den Fokus. Wenn Nutzer von assistiven Technologien mit dem LinearLayout interagieren, wird die Klickfunktion der Karte ausgelöst, ohne dass angekündigt wird, dass sie anklickbar ist. Dies führt zu einer Erfahrung, die mit unterstützender Technologie nicht barrierefrei ist, weil die Rolle oder Rollenbeschreibung des Elements nicht darauf hinweist, dass eine Aktion vorhanden ist oder was durch die Interaktion ausgelöst wird.
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:layout_margin="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_a_toast"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>Abhilfehinweis: Setzen Sie LinearLayout:focusable auf „false“
Stellen Sie sicher, dass LinearLayout keine fokussierbare Eigenschaft mit dem Wert „true“ besitzt. Standardmäßig ist der Wert auf „false“ gesetzt.
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_a_toast"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>Compose
Nicht bestandenes Beispiel
In diesem Beispiel ist das Card anklickbar, aber das untergeordnete Row erhält stattdessen den Fokus. Wenn Benutzer von Hilfstechnologien mit dem Row interagieren, wird die Klickaktion der Karte ausgelöst, aber es wird nicht angekündigt, dass sie anklickbar ist. Dies führt zu einer Erfahrung, die mit unterstützender Technologie nicht barrierefrei ist, weil die Rolle oder Rollenbeschreibung des Elements nicht darauf hinweist, dass eine Aktion vorhanden ist oder was durch die Interaktion ausgelöst wird.
Card(
modifier = Modifier
.clickable {
launchToast(context)
}
) {
Row(
modifier = Modifier
.focusable()
.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally)
) {
Text(stringResource(R.string.launch_a_toast))
}
}Abhilfehinweis: Entfernen Sie die Fokussierbarkeit des untergeordneten Elements
Hier wurde die Fokussierbarkeit des Row-Elements entfernt. Das Card kann jetzt Text vorlesen, weil es Informationen vom Text erhält. Das Card kann nun mit unterstützender Technologie fokussiert werden und liest den Textinhalt vor. Die Karte vermittelt dem Benutzer, dass sie anklickbar ist, indem sie eine Rollenbeschreibung wie „Doppeltippen zum Aktivieren“ bereitstellt, was zu einer barrierefreien Benutzererfahrung führt.
Card(
modifier = Modifier
.clickable {
launchToast(context)
}
) {
Row(
modifier = Modifier
.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally)
) {
Text(stringResource(R.string.launch_a_toast))
}
}.NET MAUI
Nicht bestandenes Beispiel
In diesem Beispiel ist das Layout anklickbar; es wurde jedoch in der Barrierefreiheitsstruktur ausgeblendet. Wenn diese Ansicht entfernt wird, fehlt die Information, dass sie als Schaltfläche dient, und Benutzer von Hilfstechnologien wissen nicht, wie sie mit dieser Ansicht interagieren können.
<Grid
HorizontalOptions="FillAndExpand"
RowDefinitions="Auto,Auto"
RowSpacing="10"
VerticalOptions="FillAndExpand"
AutomationProperties.IsInAccessibleTree="false">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Function}"/>
</Grid.GestureRecognizers>
<Label
Grid.Row="1"
FontAttributes="Bold"
FontSize="16"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<Label.FormattedText>
<FormattedString>
<Span Text="Text with a clickable parent"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>Leitfaden zur Behebung: Verwenden Sie die SemanticProperties.Hint-Eigenschaft
Barrierefreiheitsfehler können auf eine von zwei Arten behoben werden. Der einfachste Weg besteht darin, das AutomationProperties.IsInAccessibleTree="false"-Element aus der Rasteransicht zu entfernen. Falls dies mit anderen Funktionen der App in Konflikt gerät, besteht eine weitere Möglichkeit, den Nutzern die Klickaktionen bereitzustellen, darin, die SemanticProperties.Hint-Eigenschaft mit nützlichem Kontext über die Art der Ansicht zu versehen, mit der ein Nutzer interagiert – zum Beispiel "Button" oder "Switch". Dadurch kann die Assistenztechnologie den Hinweis „Zum Aktivieren doppelt tippen“ korrekt in ihre Anzeige aufnehmen und den Nutzern das nötige Feedback geben, um mit der Ansicht zu interagieren.
<Grid
HorizontalOptions="FillAndExpand"
RowDefinitions="Auto,Auto"
RowSpacing="10"
VerticalOptions="FillAndExpand">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Function}"/>
</Grid.GestureRecognizers>
<Label
Grid.Row="1"
FontAttributes="Bold"
FontSize="16"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<Label.FormattedText>
<FormattedString>
<Span Text="Text with a clickable parent"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>React Native
Nicht bestandenes Beispiel
In diesem Beispiel ist TouchableOpacity anklickbar, aber das verschachtelte View hat accessible={true}, wodurch das übergeordnete Element keinen Fokus für Barrierefreiheit erhält. Der View erhält den Fokus anstelle des anklickbaren TouchableOpacity, aber es wird nicht mitgeteilt, dass er interaktiv ist. Assistenztechnologie-Nutzer hören die Produktinformationen, wissen aber nicht, dass sie durch Antippen Details anzeigen können.
<TouchableOpacity
accessibilityRole="button"
style={styles.productCard}
onPress={() => navigateTo("product")}
>
<View accessible={true}>
<Text>Product Price</Text>
<Text>$10.00</Text>
</View>
</TouchableOpacity>Abhilfeempfehlung: Barrierefreiheitsattribute hinzufügen
In diesem überarbeiteten Beispiel sind die richtigen Barrierefreiheitsattribute direkt auf TouchableOpacity angewendet. Die Eigenschaften accessible={true} und accessibilityRole="button" stellen sicher, dass unterstützende Technologien das Element als interaktives Element ankündigen, sodass die Nutzer den Inhalt verstehen und wissen, dass er bedienbar ist.
<TouchableOpacity
accessible={true}
accessibilityRole="button"
style={styles.productCard}
onPress={() => navigateTo("product")}
>
<Text>Product Price</Text>
<Text>$10.00</Text>
</TouchableOpacity>Flutter
Nicht bestandenes Beispiel
Im folgenden Beispiel dient GestureDetector als klickbarer übergeordneter Container für Card, kann jedoch nicht selbst fokussiert werden. Der Card fungiert als Container für seine Kinder, sodass er den Fokus erhält und alle Inhalte der Kindknoten ankündigt. Wenn Benutzer von Hilfstechnologien den Fokus auf Card richten, wird die Meldung „Doppeltippen zum Aktivieren“ nicht angekündigt, da Card selbst nicht anklickbar ist, obwohl der übergeordnete GestureDetector anklickbar ist.
GestureDetector(
onTap: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Card clicked"),
behavior: SnackBarBehavior.floating,
)
),
child: const Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
"Card with clickable parent"
),
),
),
);Empfehlung zur Behebung: Verwenden Sie keinen GestureDetector-Wrapper
Hierbei fungiert das InkWell als klickbares untergeordnetes Element von Card und hat die gleichen Abmessungen wie Card. Der InkWell dient nun als Container, der allen Textinhalt Nutzern von Hilfstechnologien präsentiert. Das Ergebnis ist ein klickbares Element, das die Meldung „Doppeltippen zum Aktivieren“ ausgibt, um anzuzeigen, dass es interaktiv ist.
Card(
child: InkWell(
onTap: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Card clicked"),
behavior: SnackBarBehavior.floating,
)
),
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
"Text with clickable parent"
),
),
),
)