Content Description — vlastnost přístupnosti, která předává textový popis netextového obsahu pomocným technologiím. V iOS je to atribut accessibilityHint pro UIView, v Android — contentDescription v XML značení. Podle údajů W3C WCAG 2.2, 2023 je absence textových alternativ pro netextový obsah jedním z nejčastějších porušení přístupnosti v mobilních aplikacích. Správně vyplněné popisy činí aplikaci přístupnou pro osoby se zrakovým postižením, které používají VoiceOver a TalkBack.
Hlavní body
Content Description — řetězcová vlastnost prvku rozhraní, která předává textovou reprezentaci vizuálního obsahu pomocným technologiím. Screen reader (VoiceOver v iOS, TalkBack v Android) čte popis místo toho, aby se pokoušel vizuálně rozpoznat prvek. Popis se aplikuje na obrázky bez textové vrstvy, ikony, grafy, vlastní ovládací prvky a jakékoli netextové prvky.
Podle údajů Google Material Design, 2024 prvky bez contentDescription porušují pravidlo WCAG 1.1.1 (Non-text Content). Kontrola Accessibility Scanner ukazuje, že až 40% ikon v obchodních aplikacích nemá popis. Uživatel VoiceOver slyší pouze “obrázek” nebo “tlačítko” bez upřesnění — takové rozhraní se stává nepoužitelným pro navigaci.
Content Description nenahrazuje viditelný text prvku. Pokud tlačítko obsahuje textový štítek “Odeslat”, není nutný další popis — screen reader přečte text. Pro obrázky, ikony a vstupní pole je popis povinný.
Nástroje Accessibility Scanner (Android) a Xcode Accessibility Inspector (iOS) automaticky kontrolují přítomnost popisů. Doporučuje se provádět tyto kontroly na každé obrazovce před vydáním.
Uživatel se zrakovým postižením spoléhá na VoiceOver, aby porozuměl rozhraní. Pokud ikona košíku nemá popis, slyší pouze “tlačítko”. Aby zjistil, co tlačítko dělá, musí jej slepě stisknout — riziko nevratné akce. Popis “Odstranit produkt z košíku” řeší tento problém za sekundu.
Uživatel s dočasnými omezeními (silné slunce venku, rozbitá obrazovka) také používá VoiceOver. Podle Apple Accessibility Report, 2023 přibližně 20% uživatelů VoiceOver nemá trvalé zrakové postižení — zapínají tuto funkci situačně.
Kritérium WCAG 1.1.1 (úroveň A) vyžaduje, aby každý netextový obsah měl textovou alternativu. Výjimka: obsah, který je dekorativní, používá se pouze pro vizuální design nebo nenese informace. Test dekorativnosti: pokud prvek odstraníme, změní se význam stránky? Pokud ne — lze jej skrýt před screen readerem.
Accessibility Label (accessibilityLabel v iOS) — název prvku, který screen reader vysloví při zaostření. Content Description (accessibilityHint v iOS) — dodatečné vysvětlení, které se přečte po názvu a informuje o výsledku akce.
Rozdíl je dobře vidět na příkladu tlačítka “Košík”. Label: “Košík”. Description: “Otevře obrazovku objednávky”. VoiceOver říká: “Košík. Otevře obrazovku objednávky”. Pokud je nastaven pouze Label, uživatel nebude vědět, co se po stisknutí stane.
| Vlastnost | iOS | Android | Účel |
|---|---|---|---|
| Label | accessibilityLabel | contentDescription | Název prvku (tlačítko, pole, obrázek) |
| Description | accessibilityHint | contentDescription (rozšířená) | Vysvětlení akce nebo významu |
| Trait | accessibilityTraits | role / className | Role prvku (tlačítko, nadpis) |
Pravidlo: Label odpovídá na otázku “Co to je?”, Description — “Co se stane?”. V Android může contentDescription plnit obě role, ale v praxi je lepší je oddělit: použijte konkatenaci “[název], [vysvětlení]”.
Pro složité gesta (přejetí pro smazání, dlouhé stisknutí pro kontextovou nabídku) je accessibilityHint povinné. Uživatel VoiceOver neví o skrytých gestech, pokud nejsou popsána. Uveďte: “Přejeďte doleva pro smazání” v hintu prvku.
Na platformě iOS se accessibilityHint nastavuje prostřednictvím stejnojmenné vlastnosti UIView nebo NSObject. Hodnota — řetězec až 80 znaků. VoiceOver přečte hint po label, pokud je zapnutý režim podrobných popisů (v nastavení VoiceOver — “Verbosity”).
Příklad nastavení hint pro vlastní tlačítko:
import UIKit
class CustomButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
self.accessibilityLabel = "Přidat do oblíbených"
self.accessibilityHint = "Uloží produkt do seznamu oblíbených"
}
}
Pro UIImageView bez textového obsahu je povinné nastavit isAccessibilityElement = true a accessibilityHint:
let imageView = UIImageView(image: UIImage(named: "chart-sales"))
imageView.isAccessibilityElement = true
imageView.accessibilityHint = "Graf prodeje za poslední čtvrtletí"
VoiceOver čte: “Graf prodeje za poslední čtvrtletí”. Pokud je hint prázdný — pouze “obrázek”. Apple HIG, 2024 doporučuje nepoužívat v hintu slovesa jako “stiskněte” nebo “dotkněte se” — VoiceOver automaticky přidá instrukci gesta.
V SwiftUI se hint nastavuje pomocí řetězového modifikátoru:
Image(systemName: "trash")
.accessibilityLabel("Smazat")
.accessibilityHint("Nevratně smaže vybraný prvek")
SwiftUI automaticky kombinuje modifikátory pro složená zobrazení. Pokud je Image uvnitř Button, SwiftUI použije label tlačítka jako hlavní accessibilityLabel.
V Android se contentDescription nastavuje buď v XML značení, nebo programově přes setContentDescription(). TalkBack přečte popis při zaostření na prvek.
Příklad v XML:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_search"
android:contentDescription="Vyhledávání produktů" />
Programové nastavení pro dynamické prvky:
binding.iconSearch.contentDescription =
"Vyhledávání. Otevře obrazovku vyhledávání s filtry"
Pro dekorativní obrázky (oddělovače, pozadí, dekorativní ikony) nastavte contentDescription = "@null" nebo setContentDescription(null) — TalkBack takový prvek přeskočí. V XML: android:contentDescription="@null". Prázdný řetězec "" nefunguje — TalkBack stejně řekne “obrázek”.
Pro ImageButton vždy nastavte contentDescription — TalkBack nevidí text na obrázku. Pro CheckBox by se měl popis dynamicky měnit: “Vybráno” / “Nevybráno” místo statického popisu. Použijte setContentDescription v posluchači stavu.
Informativnost — popis by měl předávat význam, nikoli vnější vzhled. Ne “Modrá ikona s fajfkou”, ale “Produkt přidán do košíku”. Screen reader se nezajímá o barvy — zajímá se o výsledek.
Stručnost — optimální délka 2–4 slova (až 80 znaků). Dlouhé popisy zpomalují navigaci: VoiceOver čte sekvenčně, každé slovo je sekunda času uživatele. Podle Apple WWDC 2023, “Accessibility by Design” fráze delší než 5 sekund čtení přerušuje kognitivní tok.
Jedinečnost — na jedné obrazovce by neměly být dva prvky se stejným popisem. Uživatel nebude schopen rozlišit, jaký výsledek přinese zaostření na první a na druhý prvek. Pokud je několik tlačítek “Koupit” — přidejte identifikátor: “Koupit iPhone 15”, “Koupit iPhone 15 Pro”.
Lokalizace — Content Description se překládá do všech jazyků, které aplikace podporuje. Chyba lokalizace popisu je jedním z častých důvodů neúspěchu Accessibility Review v App Store.
Výzkum Nielsen Norman Group, 2024 ukázal, že optimální délka popisu pro screen reader je 3–5 slov (až 50 znaků). Delší popisy snižují rychlost navigace o 30%, protože uživatel musí čekat na dokončení čtení před dalším krokem.
Nadbytečnost — popis duplikuje viditelný text. Pokud tlačítko obsahuje text “Odeslat”, nenastavujte accessibilityHint = “Tlačítko odeslat”. VoiceOver přečte text automaticky a hint přidá zbytečný šum.
Záměna s Label — použití contentDescription místo label pro textová tlačítka. V iOS by se accessibilityLabel měl shodovat s textem tlačítka (nebo být prázdný, pokud je text již viditelný), a hint pouze vysvětluje akci. Podle Google Testing Blog, 2024 má 23% kontrolovaných aplikací v Play Store duplicitní popisy.
Ignorování dynamiky — popis se neaktualizuje při změně stavu. Například u přepínače “Wi-Fi” popis zůstává “Zapnout Wi-Fi” i po zapnutí. Správně: dynamicky změnit popis na “Vypnout Wi-Fi” sledováním stavu.
Po aktualizaci designu (změna ikon, přeuspořádání prvků) Content Description často zmizí. Důvod: designér nahrazuje obrázek, vývojář nekontroluje vlastnosti přístupnosti nového assetu. Řešení: udělat kontrolu přístupnosti povinným krokem code review — přidat kontrolní seznam s bodem “Content Description aktualizován?”.
func testContentDescriptionExists() {
let app = XCUIApplication()
app.launch()
let image = app.images["chart-sales"]
XCTAssertNotNil(image.label)
XCTAssertGreaterThan(image.label.count, 0)
}
Často kladené otázky
Uživatel VoiceOver nebo TalkBack uslyší pouze “obrázek” nebo “tlačítko” — bez uvedení účelu. To porušuje WCAG 1.1.1 a činí aplikaci nepřístupnou pro osoby se zrakovým postižením.
Ne. Pokud tlačítko obsahuje textový štítek, VoiceOver jej automaticky přečte. Popis (accessibilityHint) lze přidat pro vysvětlení výsledku stisknutí, ale Label není vyžadován.
V iOS nastavte isAccessibilityElement = false. V Android nastavte contentDescription = "@null". Screen reader takový prvek zcela přeskočí, aniž by vydával zvuk.
V iOS použijte NSLocalizedString pro accessibilityHint, v Android — řetězcové zdroje přes @string/. Překlad popisů je povinný pro všechny podporované jazyky.
Přidejte UI testy, které kontrolují přítomnost popisu pro všechny ImageView. V iOS — XCUIApplication, v Android — AccessibilityCheckRule z Espresso. Accessibility Scanner lze spustit v CI přes příkazový řádek.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také