1.4.13 - Tartalom mutató mozgás közben
Röviden a szabványpontról
A WCAG 1.4.13 (Content on Hover or Focus) előírja, hogy minden olyan kiegészítő tartalom, amely megjelenik, amikor a felhasználó egy elem fölé viszi az egeret vagy arra fókuszál (mint tooltip-ek, legördülő menük vagy felugró ablakok), meg kell feleljen bizonyos akadálymentességi követelményeknek. Ez a tartalom legyen:
- Elutasítható: A felhasználóknak képesnek kell lenniük a tartalom egyszerű elutasítására
- Lebegtethetőre: A felhasználóknak képesnek kell lenniük a mutatót a tartalomba mozgatni anélkül, hogy az eltűnne
- Állandó: A tartalomnak láthatónak kell maradnia, amíg el nem utasítják vagy a fókusz el nem mozdul
Cél: Biztosítani, hogy a billentyűzetes navigációra vagy kisegítő technológiákra támaszkodó felhasználók hozzáférjenek és interakcióba lépjenek a hover vagy fókusz által felfedett tartalommal anélkül, hogy az váratlanul eltűnne vagy elérhetetlenné válna.
Kiket érint
Elsődleges felhasználók: Mozgássérült emberek, akik billentyűzettel vagy alternatív beviteli eszközökkel navigálnak, kognitív fogyatékossággal élő felhasználók, akiknek állandó kontextusra van szükségük, és képernyőolvasó felhasználók, akik billentyűzet fókuszra támaszkodnak.
Másodlagos előnyök: Javított használhatóság minden felhasználó számára, beleértve az érintőképernyős eszközöket használókat vagy átmeneti fogyatékossággal élőket, az interaktív tartalom kiszámíthatóbbá és kezelhetőbbé tételével.
Tesztelés
Az 1.4.13 megfelelőségének ellenőrzéséhez próbáld ki a következő tesztelési módszereket:
- Csak billentyűzetes navigáció: Használd a billentyűzetet (Tab, Shift+Tab, nyilak) olyan elemekre navigáláshoz, amelyek fókuszra tartalmat fednek fel. Erősítsd meg, hogy a tartalom megjelenik és látható marad, amíg fókuszban van
- Mutató hover tesztelés: Vidd az egeret az elem fölé és mozgasd a mutatót a felfedett tartalomba. Ellenőrizd, hogy a tartalom nem tűnik el, amikor a mutatót bele mozgatod
- Elutasíthatóság ellenőrzés: Győződj meg róla, hogy van egyértelmű módja a tartalom elutasításának (pl. Escape billentyű nyomása vagy bezárás gomb) és hogy az várt módon eltűnik
- Képernyőolvasó teszt: Használj képernyőolvasót az elemre navigáláshoz és erősítsd meg, hogy a kiegészítő tartalom bejelentésre kerül és hozzáférhető
- Érintőeszköz teszt: Érintőképernyőn érintsd meg az elemet a tartalom felfedéséhez és ellenőrizd, hogy látható marad és elutasítható
Jó gyakorlatok
1. Tooltip billentyűzet támogatással
<div class="tooltip-container">
<button aria-describedby="tooltip1" id="info-btn" class="info-button">
ℹ️ Információ
</button>
<div role="tooltip" id="tooltip1" class="tooltip" hidden>
Ez a tooltip tartalom magyarázza a gomb funkcióját. Látható marad fókusz alatt és hover állapotban.
</div>
</div>
<style>
.tooltip-container {
position: relative;
display: inline-block;
margin: 20px;
}
.info-button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.info-button:hover, .info-button:focus {
background-color: #0056b3;
outline: 2px solid #80bdff;
outline-offset: 2px;
}
.tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background-color: #333;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
white-space: nowrap;
z-index: 1000;
margin-bottom: 5px;
max-width: 200px;
white-space: normal;
}
.tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: #333;
}
.tooltip:not([hidden]) {
display: block;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const btn = document.getElementById('info-btn');
const tooltip = document.getElementById('tooltip1');
let hideTimeout;
function showTooltip() {
clearTimeout(hideTimeout);
tooltip.hidden = false;
}
function hideTooltip() {
hideTimeout = setTimeout(() => {
tooltip.hidden = true;
}, 100);
}
// Megjelenítés események
btn.addEventListener('focus', showTooltip);
btn.addEventListener('mouseenter', showTooltip);
tooltip.addEventListener('mouseenter', showTooltip);
// Elrejtés események
btn.addEventListener('blur', hideTooltip);
btn.addEventListener('mouseleave', hideTooltip);
tooltip.addEventListener('mouseleave', hideTooltip);
// Escape billentyűvel való elutasítás
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && !tooltip.hidden) {
tooltip.hidden = true;
btn.focus();
}
});
});
</script>
Magyarázat: A tooltip megjelenik hover és fókusz esetén egyaránt. Csak akkor tűnik el, amikor a felhasználó elmozgatja a fókuszt vagy az egeret, és az Escape billentyűvel elutasítható.
2. Legördülő menü, amely nyitva marad hover vagy fókusz alatt
<nav class="dropdown-nav">
<ul class="main-menu">
<li class="menu-item">
<button tabindex="0" aria-haspopup="true" aria-expanded="false" id="services-menu" class="menu-button">
Szolgáltatások ▼
</button>
<ul id="services-submenu" class="submenu" hidden>
<li><a href="/webfejlesztes" class="submenu-link">Webfejlesztés</a></li>
<li><a href="/seo" class="submenu-link">SEO optimalizálás</a></li>
<li><a href="/karbantartas" class="submenu-link">Karbantartás</a></li>
</ul>
</li>
</ul>
</nav>
<style>
.dropdown-nav {
background-color: #f8f9fa;
padding: 10px;
margin: 20px 0;
}
.main-menu {
list-style: none;
margin: 0;
padding: 0;
}
.menu-item {
position: relative;
display: inline-block;
}
.menu-button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 15px;
cursor: pointer;
border-radius: 4px;
font-size: 16px;
}
.menu-button:hover, .menu-button:focus {
background-color: #0056b3;
outline: 2px solid #80bdff;
outline-offset: 2px;
}
.submenu {
position: absolute;
top: 100%;
left: 0;
background-color: white;
border: 1px solid #dee2e6;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
min-width: 200px;
z-index: 1000;
list-style: none;
margin: 0;
padding: 5px 0;
}
.submenu:not([hidden]) {
display: block;
}
.submenu-link {
display: block;
padding: 10px 15px;
color: #333;
text-decoration: none;
transition: background-color 0.2s;
}
.submenu-link:hover, .submenu-link:focus {
background-color: #f8f9fa;
outline: 2px solid #007bff;
outline-offset: -2px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const menu = document.getElementById('services-menu');
const submenu = document.getElementById('services-submenu');
const menuItem = menu.closest('.menu-item');
let closeTimeout;
function openMenu() {
clearTimeout(closeTimeout);
submenu.hidden = false;
menu.setAttribute('aria-expanded', 'true');
}
function closeMenu() {
closeTimeout = setTimeout(() => {
submenu.hidden = true;
menu.setAttribute('aria-expanded', 'false');
}, 100);
}
function immediateClose() {
clearTimeout(closeTimeout);
submenu.hidden = true;
menu.setAttribute('aria-expanded', 'false');
}
// Megnyitás események
menu.addEventListener('focus', openMenu);
menu.addEventListener('mouseenter', openMenu);
menuItem.addEventListener('mouseenter', openMenu);
// Bezárás események
menu.addEventListener('blur', closeMenu);
menuItem.addEventListener('mouseleave', closeMenu);
// Escape billentyűvel bezárás
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && !submenu.hidden) {
immediateClose();
menu.focus();
}
});
// Submenu linkek kezelése
const submenuLinks = submenu.querySelectorAll('.submenu-link');
submenuLinks.forEach(link => {
link.addEventListener('blur', function(e) {
// Ha az utolsó elemről lépünk ki és nem maradunk az almenün belül
if (!submenu.contains(e.relatedTarget)) {
closeMenu();
}
});
});
});
</script>
Magyarázat: Az almenü nyitva marad, amíg hover vagy fókusz állapotban van. Az ARIA attribútumok kommunikálják a menü állapotát, és a billentyűzet felhasználók navigálhatnak az almenü elemei között.
3. Elutasítható felugró ablak
<div class="help-section">
<button id="help-trigger" aria-haspopup="dialog" aria-controls="help-dialog" class="help-button">
❓ Súgó
</button>
<div id="help-dialog" role="dialog" aria-labelledby="help-title" class="help-dialog" hidden>
<div class="dialog-content">
<h3 id="help-title">Súgó információ</h3>
<p>Ez hasznos információ a funkció használatáról. A dialógus nyitva marad, amíg be nem zárod vagy el nem navigálsz róla.</p>
<button id="close-help" class="close-button">✕ Bezárás</button>
</div>
</div>
</div>
<style>
.help-section {
position: relative;
margin: 20px;
}
.help-button {
background-color: #28a745;
color: white;
border: none;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.help-button:hover, .help-button:focus {
background-color: #218838;
outline: 2px solid #80e5a3;
outline-offset: 2px;
}
.help-dialog {
position: absolute;
top: 100%;
left: 0;
background-color: white;
border: 2px solid #007bff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
padding: 0;
z-index: 1001;
min-width: 300px;
max-width: 400px;
}
.help-dialog:not([hidden]) {
display: block;
}
.dialog-content {
padding: 20px;
}
.dialog-content h3 {
margin: 0 0 10px 0;
color: #333;
font-size: 16px;
}
.dialog-content p {
margin: 0 0 15px 0;
color: #666;
line-height: 1.5;
}
.close-button {
background-color: #dc3545;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
float: right;
}
.close-button:hover, .close-button:focus {
background-color: #c82333;
outline: 2px solid #f5c6cb;
outline-offset: 2px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const helpBtn = document.getElementById('help-trigger');
const helpDialog = document.getElementById('help-dialog');
const closeBtn = document.getElementById('close-help');
let isDialogOpen = false;
function openDialog() {
helpDialog.hidden = false;
isDialogOpen = true;
// Fókusz a dialógusba (első fókuszálható elemre)
closeBtn.focus();
}
function closeDialog() {
helpDialog.hidden = true;
isDialogOpen = false;
// Fókusz visszaadása a kiváltó gombnak
helpBtn.focus();
}
// Dialógus megnyitása
helpBtn.addEventListener('click', function(e) {
e.preventDefault();
openDialog();
});
helpBtn.addEventListener('focus', function() {
setTimeout(openDialog, 500); // Kis késleltetés a véletlenszerű megnyitás elkerülésére
});
// Dialógus bezárása
closeBtn.addEventListener('click', closeDialog);
// Escape billentyűvel bezárás
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && isDialogOpen) {
closeDialog();
}
});
// Kattintás a dialóguson kívül
document.addEventListener('click', function(e) {
if (isDialogOpen && !helpDialog.contains(e.target) && e.target !== helpBtn) {
closeDialog();
}
});
// Fókusz kezelés - bezárás, ha a fókusz elhagyja a dialógust
helpDialog.addEventListener('focusout', function(e) {
setTimeout(() => {
if (isDialogOpen && !helpDialog.contains(document.activeElement)) {
closeDialog();
}
}, 10);
});
});
</script>
Magyarázat: A dialógus megnyílik fókuszra és bezárás gombbal, Escape billentyűvel vagy fókusz elhagyásával elutasítható. A fókusz kezelés visszatér a kiváltó gombhoz bezárás után.
4. Accordion panel hover és fókusz támogatással
<div class="accordion-container">
<div class="accordion-item">
<button id="accordion-btn-1" aria-expanded="false" aria-controls="accordion-panel-1" class="accordion-header">
Gyakori kérdések ▼
</button>
<div id="accordion-panel-1" class="accordion-panel" hidden>
<p>Itt találod a leggyakrabban feltett kérdéseket és válaszokat. Ez a panel nyitva marad, amíg aktív fókuszban vagy hover állapotban van.</p>
<ul>
<li><a href="#faq1">Hogyan regisztrálhatok?</a></li>
<li><a href="#faq2">Milyen fizetési módokat fogadnak el?</a></li>
<li><a href="#faq3">Mennyi a szállítási idő?</a></li>
</ul>
</div>
</div>
</div>
<style>
.accordion-container {
max-width: 500px;
margin: 20px auto;
border: 1px solid #dee2e6;
border-radius: 8px;
overflow: hidden;
}
.accordion-item {
position: relative;
}
.accordion-header {
width: 100%;
background-color: #f8f9fa;
border: none;
padding: 15px 20px;
text-align: left;
cursor: pointer;
font-size: 16px;
font-weight: 600;
color: #333;
transition: background-color 0.2s;
}
.accordion-header:hover, .accordion-header:focus {
background-color: #e9ecef;
outline: 2px solid #007bff;
outline-offset: -2px;
}
.accordion-header[aria-expanded="true"] {
background-color: #007bff;
color: white;
}
.accordion-panel {
background-color: white;
padding: 20px;
border-top: 1px solid #dee2e6;
}
.accordion-panel:not([hidden]) {
display: block;
}
.accordion-panel ul {
list-style-type: disc;
padding-left: 20px;
}
.accordion-panel li {
margin-bottom: 8px;
}
.accordion-panel a {
color: #007bff;
text-decoration: none;
}
.accordion-panel a:hover, .accordion-panel a:focus {
text-decoration: underline;
outline: 2px solid #80bdff;
outline-offset: 2px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const accordionBtn = document.getElementById('accordion-btn-1');
const accordionPanel = document.getElementById('accordion-panel-1');
const accordionItem = accordionBtn.closest('.accordion-item');
let closeTimeout;
let isExpanded = false;
function expandPanel() {
clearTimeout(closeTimeout);
accordionPanel.hidden = false;
accordionBtn.setAttribute('aria-expanded', 'true');
accordionBtn.innerHTML = 'Gyakori kérdések ▲';
isExpanded = true;
}
function collapsePanel() {
closeTimeout = setTimeout(() => {
accordionPanel.hidden = true;
accordionBtn.setAttribute('aria-expanded', 'false');
accordionBtn.innerHTML = 'Gyakori kérdések ▼';
isExpanded = false;
}, 200);
}
function immediateCollapse() {
clearTimeout(closeTimeout);
accordionPanel.hidden = true;
accordionBtn.setAttribute('aria-expanded', 'false');
accordionBtn.innerHTML = 'Gyakori kérdések ▼';
isExpanded = false;
}
// Kattintás kezelés
accordionBtn.addEventListener('click', function() {
if (isExpanded) {
immediateCollapse();
} else {
expandPanel();
}
});
// Hover események
accordionItem.addEventListener('mouseenter', expandPanel);
accordionItem.addEventListener('mouseleave', collapsePanel);
// Fókusz események
accordionBtn.addEventListener('focus', expandPanel);
// Panel fókusz kezelés
accordionPanel.addEventListener('focusout', function(e) {
if (!accordionItem.contains(e.relatedTarget)) {
collapsePanel();
}
});
// Escape billentyű
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && isExpanded) {
immediateCollapse();
accordionBtn.focus();
}
});
});
</script>
Magyarázat: Az accordion panel automatikusan kinyílik hover és fókusz esetén, és nyitva marad, amíg a felhasználó aktívan interakcióban van vele.
Rossz gyakorlatok
Tartalom azonnal eltűnik, amikor a mutató elhagyja a kiváltó elemet
<button id="bad-tooltip-trigger">Rossz tooltip</button>
<div id="bad-tooltip" class="bad-tooltip" style="display: none;">
Ez a tooltip eltűnik, mielőtt elérnéd
</div>
<script>
// ROSSZ MEGVALÓSÍTÁS
document.getElementById('bad-tooltip-trigger').addEventListener('mouseenter', function() {
document.getElementById('bad-tooltip').style.display = 'block';
});
document.getElementById('bad-tooltip-trigger').addEventListener('mouseleave', function() {
document.getElementById('bad-tooltip').style.display = 'none'; // Azonnal eltűnik
});
</script>
Probléma: A tartalom azonnal eltűnik, amikor a mutató elhagyja a kiváltó elemet, megakadályozva a felhasználókat abban, hogy interakcióba lépjenek vele.
Nincs billentyűzet támogatás a tartalom felfedéséhez vagy elutasításához
<div class="hover-only-content">
<span>Csak hover-re reagál</span>
<div class="hover-tooltip">Csak egérrel elérhető tooltip</div>
</div>
<style>
.hover-tooltip {
display: none;
position: absolute;
background: #333;
color: white;
padding: 5px;
}
.hover-only-content:hover .hover-tooltip {
display: block; /* Csak hover-re jelenik meg, fókuszra nem */
}
</style>
Probléma: A csak hover-re reagáló tartalom kizárja a billentyűzet felhasználókat, akik nem tudják elérni a tartalmat.
Tartalom megjelenik, de nem utasítható el vagy fókusz csapdát okoz
<button id="problematic-trigger">Problémás trigger</button>
<div id="problematic-popup" class="problematic-popup" style="display: none;">
<p>Ez a popup nem utasítható el megfelelően</p>
<!-- Nincs bezárás gomb és nem reagál Escape-re -->
</div>
<script>
document.getElementById('problematic-trigger').addEventListener('click', function() {
document.getElementById('problematic-popup').style.display = 'block';
// Nincs elutasítási mechanizmus
});
</script>
Probléma: A popup megjelenik, de nincs egyértelmű módja az elutasításnak, ami akadálymentességi problémát és frusztrációt okoz.
Natív title attribútum használata tooltip-ként
<button id="native-title-btn" title="Ez a natív tooltip szöveg">
Hover me (rossz példa)
</button>
Probléma: A natív title attribútum tooltip nem elérhető billentyűzettel és eltűnik egér elhagyáskor, nem felel meg a kritériumnak.
Rövid időzítés vagy automatikus elrejtés
<button id="auto-hide-trigger">Automatikusan elrejtő tartalom</button>
<div id="auto-hide-content" style="display: none;">
Ez a tartalom automatikusan eltűnik
</div>
<script>
document.getElementById('auto-hide-trigger').addEventListener('focus', function() {
const content = document.getElementById('auto-hide-content');
content.style.display = 'block';
// ROSSZ: Automatikus elrejtés rövid idő után
setTimeout(() => {
content.style.display = 'none';
}, 2000); // 2 másodperc után eltűnik, függetlenül a felhasználó interakciójától
});
</script>
Probléma: Az automatikus elrejtés nem ad elegendő időt a felhasználóknak a tartalom elolvasására vagy interakcióra, különösen a kisegítő technológiát használó felhasználóknak.
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!