4.1.2 - Név, szerep, érték
Röviden a szabványpontról
A WCAG 2.2 Success Criterion 4.1.2 megköveteli, hogy minden felhasználói felület komponens esetében a név, szerep és érték programozottan meghatározható legyen a kisegítő technológiák számára. Ez azt jelenti, hogy a képernyőolvasók és más kisegítő eszközök képesek azonosítani, hogy mi az elem (szerep), hogyan hívják vagy címkézik (név), és mi a jelenlegi állapota vagy értéke (érték).
Cél: Biztosítani, hogy a kisegítő technológiákra támaszkodó felhasználók hatékonyan érzékelhessék és használhassák a tartalmat, valamint megértsék a felhasználói felület komponensek aktuális állapotát. Ez alapvető követelmény minden interaktív elem hozzáférhetőségéhez.
Mire vonatkozik: Minden interaktív felhasználói felület elemre, mint például gombok, űrlapmezők, csúszkák, jelölőnégyzetek és egyedi vezérlők. A kritérium biztosítja, hogy ezek az elemek teljes mértékben hozzáférhetők legyenek.
Kiket érint
Elsődleges felhasználók: Képernyőolvasót vagy más kisegítő technológiákat használó emberek, akik a programozottan elérhető információkra támaszkodnak a webes tartalmak navigálásához és használatához. Pontos név, szerep és érték nélkül ezek a felhasználók nem tudják megérteni vagy irányítani a felület elemeket.
Másodlagos előnyök: A világos programozási információk javítják a kompatibilitást az automatizált tesztelő eszközökkel és hangvezérlő rendszerekkel, ami hasznos a mozgásszervi vagy kognitív fogyatékossággal élő felhasználók számára is.
Tesztelés
- Képernyőolvasó használata: Navigálj a felhasználói felület elemeken és győződj meg róla, hogy a képernyőolvasó helyesen mondja be az elem nevét, szerepét és aktuális értékét
- ARIA attribútumok vizsgálata: Ellenőrizd, hogy a szerepek (role), nevek (aria-label, aria-labelledby vagy natív címkézés útján) és állapotok/értékek (pl. aria-checked, aria-valuenow) helyesen vannak-e alkalmazva
- Böngésző akadálymentességi eszközök használata: Az eszközök, mint a Chrome DevTools Accessibility panel vagy Firefox Accessibility Inspector megmutatják az elemek hozzáférhető nevét, szerepét és értékét
- Automatizált akadálymentességi vizsgálatok futtatása: Használj axe DevTools vagy axe Linter eszközöket a hiányzó vagy helytelen ARIA szerepek, nevek vagy értékek észlelésére
- Billentyűzetes tesztelés: Biztosítsd, hogy az interaktív elemek programozottan jelzik állapotváltozásaikat billentyűzetes interakció során
Jó gyakorlatok
1. Natív HTML elemek használata
<!-- NATÍV HTML GOMBOK ÉS ŰRLAPELEMEK -->
<form class="contact-form">
<div class="form-header">
<h2>Kapcsolatfelvételi űrlap</h2>
<p>Töltse ki az alábbi mezőket, hogy felvegyük Önnel a kapcsolatot</p>
</div>
<!-- Natív gomb - automatikusan rendelkezik "button" szereppel és "Küldés" névvel -->
<div class="form-group">
<button type="submit" id="submitBtn" class="btn-primary">
Küldés
</button>
</div>
<!-- Natív szöveges beviteli mező explicit címkével -->
<div class="form-group">
<label for="nev">Teljes név</label>
<input
type="text"
id="nev"
name="nev"
required
aria-describedby="nev-help"
>
<span id="nev-help" class="field-help">
Adja meg teljes nevét (vezetéknév és keresztnév)
</span>
</div>
<!-- Natív email mező -->
<div class="form-group">
<label for="email">E-mail cím</label>
<input
type="email"
id="email"
name="email"
required
placeholder="pelda@email.hu"
>
<!-- A type="email" automatikusan közli a szerepet -->
</div>
<!-- Natív jelölőnégyzet -->
<div class="form-group">
<label>
<input
type="checkbox"
name="hirlevel"
value="feliratkozas"
>
Szeretnék hírlevelet kapni
</label>
<!-- A checkbox automatikusan rendelkezik szereppel és állapottal -->
</div>
<!-- Natív választó lista -->
<div class="form-group">
<label for="orszag">Ország</label>
<select id="orszag" name="orszag" required>
<option value="">Válasszon országot</option>
<option value="hu">Magyarország</option>
<option value="at">Ausztria</option>
<option value="de">Németország</option>
</select>
<!-- A select elem automatikusan közli szerepét és aktuális értékét -->
</div>
<!-- Natív rádiógombok -->
<fieldset>
<legend>Preferált kapcsolatfelvételi mód</legend>
<div class="radio-group">
<label>
<input type="radio" name="kapcsolat" value="email" checked>
E-mail
</label>
<label>
<input type="radio" name="kapcsolat" value="telefon">
Telefon
</label>
<label>
<input type="radio" name="kapcsolat" value="posta">
Postai levél
</label>
</div>
</fieldset>
</form>
<script>
// A natív elemek automatikusan kezelik az állapotváltozásokat
document.getElementById('submitBtn').addEventListener('click', function(e) {
e.preventDefault();
// A gomb disabled állapota automatikusan közlésre kerül
this.disabled = true;
this.textContent = 'Küldés folyamatban...';
// Szimulált küldés
setTimeout(() => {
this.disabled = false;
this.textContent = 'Elküldve!';
// Képernyőolvasó értesítése
const statusMsg = document.createElement('div');
statusMsg.setAttribute('role', 'status');
statusMsg.setAttribute('aria-live', 'polite');
statusMsg.textContent = 'Az űrlap sikeresen elküldve.';
document.body.appendChild(statusMsg);
}, 2000);
});
</script>
2. Egyedi kapcsoló ARIA attribútumokkal
<!-- EGYEDI KAPCSOLÓ VEZÉRLŐK -->
<div class="settings-panel">
<h2>Beállítások</h2>
<!-- Egyedi kapcsoló teljes ARIA támogatással -->
<div class="setting-item">
<span id="repules-mod-cimke">Repülési mód</span>
<div
role="switch"
aria-checked="false"
aria-labelledby="repules-mod-cimke"
tabindex="0"
class="custom-switch"
id="repules-mod-kapcsolo"
>
<span class="switch-handle"></span>
</div>
<span id="repules-mod-leiras" class="setting-description">
Kikapcsolja az összes vezeték nélküli kapcsolatot
</span>
</div>
<!-- Egyedi jelölőnégyzet ARIA-val -->
<div class="setting-item">
<div
role="checkbox"
aria-checked="false"
aria-label="Értesítések engedélyezése"
aria-describedby="ertesites-leiras"
tabindex="0"
class="custom-checkbox"
id="ertesites-checkbox"
>
<svg class="checkmark" aria-hidden="true" width="18" height="18">
<path d="M6.61 11.89L3.5 8.78 2.44 9.84 6.61 14l8.95-8.95L14.5 4z" fill="currentColor"/>
</svg>
</div>
<label for="ertesites-checkbox">Értesítések engedélyezése</label>
<span id="ertesites-leiras" class="setting-description">
Push értesítések fogadása új üzenetekről
</span>
</div>
<!-- Egyedi többállapotú gomb -->
<div class="setting-item">
<span id="tema-cimke">Téma választás</span>
<div
role="button"
aria-pressed="false"
aria-labelledby="tema-cimke"
aria-describedby="tema-allapot"
tabindex="0"
class="theme-toggle"
id="tema-valto"
>
<svg aria-hidden="true" width="24" height="24">
<circle cx="12" cy="12" r="5"/>
<line x1="12" y1="1" x2="12" y2="3"/>
<line x1="12" y1="21" x2="12" y2="23"/>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
</svg>
<span id="tema-allapot" class="sr-only">Világos téma aktív</span>
</div>
</div>
</div>
<script>
// Repülési mód kapcsoló kezelése
const repulesModKapcsolo = document.getElementById('repules-mod-kapcsolo');
function toggleRepulesmod() {
const isChecked = repulesModKapcsolo.getAttribute('aria-checked') === 'true';
const ujAllapot = !isChecked;
// ARIA állapot frissítése
repulesModKapcsolo.setAttribute('aria-checked', ujAllapot);
// Vizuális állapot frissítése
if (ujAllapot) {
repulesModKapcsolo.classList.add('checked');
} else {
repulesModKapcsolo.classList.remove('checked');
}
// Képernyőolvasó értesítése
const statusMsg = document.createElement('div');
statusMsg.setAttribute('role', 'status');
statusMsg.setAttribute('aria-live', 'polite');
statusMsg.textContent = `Repülési mód ${ujAllapot ? 'bekapcsolva' : 'kikapcsolva'}`;
document.body.appendChild(statusMsg);
setTimeout(() => document.body.removeChild(statusMsg), 3000);
}
repulesModKapcsolo.addEventListener('click', toggleRepulesmod);
repulesModKapcsolo.addEventListener('keydown', function(e) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
toggleRepulesmod();
}
});
// Egyedi jelölőnégyzet kezelése
const ertesitesCheckbox = document.getElementById('ertesites-checkbox');
function toggleErtesites() {
const isChecked = ertesitesCheckbox.getAttribute('aria-checked') === 'true';
const ujAllapot = !isChecked;
ertesitesCheckbox.setAttribute('aria-checked', ujAllapot);
if (ujAllapot) {
ertesitesCheckbox.classList.add('checked');
} else {
ertesitesCheckbox.classList.remove('checked');
}
}
ertesitesCheckbox.addEventListener('click', toggleErtesites);
ertesitesCheckbox.addEventListener('keydown', function(e) {
if (e.key === ' ') {
e.preventDefault();
toggleErtesites();
}
});
// Téma váltó kezelése
const temaValto = document.getElementById('tema-valto');
const temaAllapot = document.getElementById('tema-allapot');
function valtTema() {
const isPressed = temaValto.getAttribute('aria-pressed') === 'true';
const ujAllapot = !isPressed;
temaValto.setAttribute('aria-pressed', ujAllapot);
// Állapot szöveg frissítése
temaAllapot.textContent = ujAllapot ? 'Sötét téma aktív' : 'Világos téma aktív';
// Vizuális változás
document.body.classList.toggle('dark-theme', ujAllapot);
}
temaValto.addEventListener('click', valtTema);
temaValto.addEventListener('keydown', function(e) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
valtTema();
}
});
</script>
<style>
.custom-switch {
width: 48px;
height: 24px;
background: #ccc;
border-radius: 12px;
position: relative;
cursor: pointer;
transition: background 0.3s;
}
.custom-switch.checked {
background: #4caf50;
}
.switch-handle {
position: absolute;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: transform 0.3s;
}
.custom-switch.checked .switch-handle {
transform: translateX(24px);
}
.custom-checkbox {
width: 24px;
height: 24px;
border: 2px solid #666;
border-radius: 4px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.custom-checkbox .checkmark {
display: none;
}
.custom-checkbox.checked .checkmark {
display: block;
}
.sr-only {
position: absolute;
left: -10000px;
width: 1px;
height: 1px;
overflow: hidden;
}
</style>
3. Dinamikus érték frissítések
<!-- DINAMIKUS ÉRTÉKEK ÉS ÁLLAPOTOK -->
<div class="media-controls">
<h2>Médialejátszó vezérlők</h2>
<!-- Hangerő csúszka dinamikus értékkel -->
<div class="control-group">
<label for="hangero" id="hangero-cimke">Hangerő</label>
<input
type="range"
id="hangero"
min="0"
max="100"
value="50"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-labelledby="hangero-cimke"
aria-describedby="hangero-ertek"
>
<output id="hangero-ertek" for="hangero" aria-live="polite">50%</output>
</div>
<!-- Lejátszási folyamatjelző -->
<div class="control-group">
<span id="lejatszas-cimke">Lejátszási pozíció</span>
<div
role="progressbar"
aria-labelledby="lejatszas-cimke"
aria-valuemin="0"
aria-valuemax="300"
aria-valuenow="0"
aria-valuetext="0 perc 0 másodperc a 5 percből"
class="playback-progress"
id="lejatszas-folyamat"
>
<div class="progress-fill" style="width: 0%"></div>
</div>
<span id="ido-kijelzo">0:00 / 5:00</span>
</div>
<!-- Betöltési állapot -->
<div class="control-group">
<button
type="button"
id="toltes-gomb"
aria-busy="false"
aria-live="polite"
>
Videó betöltése
</button>
<div
role="status"
aria-live="polite"
id="toltes-allapot"
class="loading-status"
></div>
</div>
<!-- Egyedi értékelés komponens -->
<div class="control-group">
<span id="ertekeles-cimke">Értékelje ezt a tartalmat</span>
<div
role="slider"
aria-labelledby="ertekeles-cimke"
aria-valuemin="1"
aria-valuemax="5"
aria-valuenow="3"
aria-valuetext="3 csillag az 5-ből"
tabindex="0"
class="star-rating"
id="csillag-ertekeles"
>
<span class="star" data-rating="1">★</span>
<span class="star" data-rating="2">★</span>
<span class="star" data-rating="3">★</span>
<span class="star" data-rating="4">☆</span>
<span class="star" data-rating="5">☆</span>
</div>
</div>
</div>
<script>
// Hangerő csúszka dinamikus frissítése
const hangeroSlider = document.getElementById('hangero');
const hangeroErtek = document.getElementById('hangero-ertek');
hangeroSlider.addEventListener('input', function() {
const ertek = this.value;
// ARIA érték frissítése
this.setAttribute('aria-valuenow', ertek);
// Kijelző frissítése
hangeroErtek.textContent = ertek + '%';
// Speciális állapotok
if (ertek == 0) {
this.setAttribute('aria-valuetext', 'Némítva');
} else if (ertek == 100) {
this.setAttribute('aria-valuetext', 'Maximum hangerő');
} else {
this.removeAttribute('aria-valuetext');
}
});
// Lejátszási folyamat szimulálása
let lejatszasIdo = 0;
const maxIdo = 300; // 5 perc másodpercben
function frissitLejatszas() {
if (lejatszasIdo <= maxIdo) {
const folyamat = document.getElementById('lejatszas-folyamat');
const szazalek = (lejatszasIdo / maxIdo) * 100;
// ARIA értékek frissítése
folyamat.setAttribute('aria-valuenow', lejatszasIdo);
const percek = Math.floor(lejatszasIdo / 60);
const masodpercek = lejatszasIdo % 60;
folyamat.setAttribute('aria-valuetext',
`${percek} perc ${masodpercek} másodperc a 5 percből`);
// Vizuális frissítés
folyamat.querySelector('.progress-fill').style.width = szazalek + '%';
document.getElementById('ido-kijelzo').textContent =
`${percek}:${masodpercek.toString().padStart(2, '0')} / 5:00`;
lejatszasIdo++;
}
}
// 1 másodpercenként frissít
setInterval(frissitLejatszas, 1000);
// Betöltési állapot kezelése
const toltesGomb = document.getElementById('toltes-gomb');
const toltesAllapot = document.getElementById('toltes-allapot');
toltesGomb.addEventListener('click', function() {
// Betöltés indítása
this.setAttribute('aria-busy', 'true');
this.disabled = true;
this.textContent = 'Betöltés...';
toltesAllapot.textContent = 'Videó betöltése folyamatban...';
// Szimulált betöltés
setTimeout(() => {
this.setAttribute('aria-busy', 'false');
this.disabled = false;
this.textContent = 'Videó betöltve';
toltesAllapot.textContent = 'A videó sikeresen betöltődött.';
}, 3000);
});
// Csillag értékelés kezelése
const csillagErtekeles = document.getElementById('csillag-ertekeles');
const csillagok = csillagErtekeles.querySelectorAll('.star');
let aktualisErtekeles = 3;
function frissitCsillagok(ertek) {
aktualisErtekeles = ertek;
// ARIA frissítése
csillagErtekeles.setAttribute('aria-valuenow', ertek);
csillagErtekeles.setAttribute('aria-valuetext', `${ertek} csillag az 5-ből`);
// Vizuális frissítés
csillagok.forEach((csillag, index) => {
csillag.textContent = index < ertek ? '★' : '☆';
});
}
// Egér interakció
csillagok.forEach(csillag => {
csillag.addEventListener('click', function() {
const ertek = parseInt(this.dataset.rating);
frissitCsillagok(ertek);
});
});
// Billentyűzet navigáció
csillagErtekeles.addEventListener('keydown', function(e) {
if (e.key === 'ArrowRight' && aktualisErtekeles < 5) {
frissitCsillagok(aktualisErtekeles + 1);
} else if (e.key === 'ArrowLeft' && aktualisErtekeles > 1) {
frissitCsillagok(aktualisErtekeles - 1);
} else if (e.key === 'Home') {
frissitCsillagok(1);
} else if (e.key === 'End') {
frissitCsillagok(5);
}
});
</script>
<style>
.playback-progress {
width: 100%;
height: 8px;
background: #e0e0e0;
border-radius: 4px;
overflow: hidden;
margin: 8px 0;
}
.progress-fill {
height: 100%;
background: #2196f3;
transition: width 0.3s;
}
.star-rating {
font-size: 24px;
cursor: pointer;
}
.star {
color: #ffd700;
padding: 0 4px;
}
.star:hover {
transform: scale(1.2);
}
.loading-status {
margin-top: 8px;
color: #666;
font-style: italic;
}
</style>
Helytelen megoldások
Kerülendő megoldások:
- Hiányzó szerep és név az egyedi vezérlőn: Egyedi elemek használata szerep és hozzáférhető név nélkül
- Csak vizuális szöveg használata programozási név nélkül: A hozzáférhető név hiányozhat, ha a szöveg nincs megfelelően hivatkozva
- ARIA állapot dinamikus frissítésének hiánya: A kisegítő technológiák felhasználói nem tudják, hogy a vezérlő állapota megváltozott
- Helytelen vagy hiányzó ARIA attribútumok: Rossz szerepek vagy hiányzó értékek használata
1. Hiányzó szerep és név egyedi vezérlőn
<!-- ROSSZ GYAKORLAT - Hiányzó szerep és név -->
<div tabindex="0" onclick="toggle()">
Kapcsoló
</div>
<!-- Nincs role, nincs hozzáférhető név -->
<!-- Képernyőolvasók nem tudják azonosítani mint kapcsolót -->
<script>
function toggle() {
// Funkció van, de nem kommunikálja mi történik
event.target.classList.toggle('active');
}
</script>
2. Csak vizuális szöveg használata programozási név nélkül
<!-- ROSSZ GYAKORLAT - Csak vizuális szöveg -->
<div role="button" tabindex="0" onclick="performAction()">
<span>Kattints ide</span>
</div>
<!-- Nincs aria-label vagy aria-labelledby a szövegre hivatkozva -->
<!-- A képernyőolvasó nem biztos, hogy felismeri a szöveget mint nevet -->
<!-- ROSSZ GYAKORLAT - Ikonos gomb szöveg nélkül -->
<button type="button" onclick="deleteItem()">
<svg width="16" height="16">
<path d="M3 6l3 3 6-6"/>
</svg>
</button>
<!-- Nincs aria-label vagy szöveges tartalom -->
3. ARIA állapot dinamikus frissítésének hiánya
<!-- ROSSZ GYAKORLAT - Állapot nem frissül -->
<div
role="checkbox"
aria-checked="false"
tabindex="0"
onclick="toggleCheck()"
>
Feltételek elfogadása
</div>
<script>
function toggleCheck() {
// A vizuális állapot változik, de aria-checked NEM frissül!
event.target.classList.toggle('checked');
// Hiányzik: event.target.setAttribute('aria-checked', 'true');
}
</script>
<!-- ROSSZ GYAKORLAT - Dinamikus értékek nem frissülnek -->
<div
role="slider"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
tabindex="0"
>
<div class="slider-handle"></div>
</div>
<script>
// A vizuális pozíció változik, de aria-valuenow nem frissül
function updateSlider(newValue) {
// Hiányzik az ARIA frissítés
document.querySelector('.slider-handle').style.left = newValue + '%';
}
</script>
4. Hiányzó űrlap címkék
<!-- ROSSZ GYAKORLAT - Hiányzó címke -->
<input type="text" placeholder="Név">
<!-- Csak placeholder, nincs label vagy aria-label -->
<!-- ROSSZ GYAKORLAT - Társítatlan címke -->
<label>E-mail cím</label>
<input type="email">
<!-- A label nincs társítva az input-tal -->
<!-- ROSSZ GYAKORLAT - Rejtett címke megfelelő hivatkozás nélkül -->
<span style="display: none;">Jelszó</span>
<input type="password">
<!-- A rejtett szöveg nem érhető el -->
5. Helytelen ARIA szerepek használata
<!-- ROSSZ GYAKORLAT - Helytelen ARIA használat -->
<div role="link" onclick="submit()">Küldés</div>
<!-- Link szerep gomb funkciónál - félrevezető -->
<!-- ROSSZ GYAKORLAT - Felesleges role natív elemeken -->
<button role="button">Gomb</button>
<!-- A natív button már rendelkezik button szereppel -->
<!-- ROSSZ GYAKORLAT - Ütköző szerepek -->
<input type="checkbox" role="button">
<!-- A checkbox és button szerepek ütköznek -->
6. Dinamikus tartalom értesítés nélkül
<!-- ROSSZ GYAKORLAT - Dinamikus tartalom értesítés nélkül -->
<div id="eredmeny"></div>
<button onclick="loadResult()">Eredmény betöltése</button>
<script>
function loadResult() {
// Az eredmény megjelenik, de nincs aria-live
document.getElementById('eredmeny').textContent = 'Sikeres művelet!';
// Hiányzik: role="status" vagy aria-live="polite"
}
</script>
<!-- ROSSZ GYAKORLAT - Hibaüzenetek értesítés nélkül -->
<form>
<input type="email" id="email-input">
<div id="error-message" style="display: none; color: red;"></div>
</form>
<script>
function showError(message) {
const errorDiv = document.getElementById('error-message');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
// Hiányzik: aria-live vagy role="alert"
}
</script>
Források
Iratkozz fel hírlevelünkre!
Amennyiben szeretnél első kézből értesülni az új bejegyzésekről, iratkozz fel hírlevelünkre!