2.4.7 - Látható fókusz
Röviden a szabványpontról
A WCAG 2.4.7 (Focus Visible) előírja, hogy minden billentyűzettel működtethető felhasználói felület rendelkezzen látható billentyűzet fókusz jelzővel. Ez azt jelenti, hogy amikor a felhasználók billentyűzettel navigálnak az oldalon (pl. Tab billentyű), egyértelműen látható legyen, melyik elem van éppen fókuszban.
Mire vonatkozik: Minden interaktív elemre, mint linkek, gombok, űrlap mezők és egyéni widgetek.
Cél: Biztosítani, hogy a billentyűzetes navigációra támaszkodó felhasználók:
- Vizuálisan követhessék pozíciójukat az oldalon
- Ne kerüljenek zavarba
- Javuljon a használhatóság élményük
- Egyértelműen lássák az aktív elemet
Kiket érint
Elsődleges felhasználók: Azok, akik mozgáskorlátozottság, látáskárosodás, vagy ideiglenes sérülés miatt nem tudnak egeret használni és erősen támaszkodnak a billentyűzetes navigációra.
Másodlagos előnyök: A látható fókusz segít minden felhasználónak, beleértve a haladó felhasználókat, akik hatékonyabban használják a billentyűparancsokat és a kognitív fogyatékossággal élőket, akik profitálnak az egyértelmű vizuális jelzésekből.
Tesztelés
- Billentyűzetes navigációs teszt: Használd a Tab billentyűt az összes interaktív elemen való végignavigáláshoz. Győződj meg róla, hogy a fókusz keret, vagy kiemelés egyértelműen látható minden elemen
- Egyéni fókusz stílusok ellenőrzése: Vizsgáld meg az egyéni CSS-sel rendelkező elemeket, hogy rendelkeznek-e látható fókusz stílussal, amely megfelel a kontrasztkövetelményeknek
- Képernyőnagyító tesztelés: Nagyítsd fel az oldalt és ellenőrizd, hogy a fókusz jelző látható marad-e és nem vágódik-e le, vagy takarják-e el
- Automatizált eszközök: Használj akadálymentességi tesztelő eszközöket, mint az axe DevTools, vagy böngésző bővítmények, amelyek jelentik a hiányzó, vagy nem megfelelő fókusz jelzőket
- Több böngészős tesztelés: Ellenőrizd a fókusz láthatóságát több böngészőben és operációs rendszeren, mivel az alapértelmezett fókusz stílusok változhatnak
Jó gyakorlatok
1. Alapértelmezett böngésző fókusz használata
<!-- Jó: Alapértelmezett fókusz körvonal látható -->
<nav>
<ul>
<li><a href="/fooldal">Főoldal</a></li>
<li><a href="/termekek">Termékek</a></li>
<li><a href="/kapcsolat">Kapcsolat</a></li>
</ul>
</nav>
<!-- Jó: Űrlap elemek alapértelmezett fókusszal -->
<form>
<label for="nev">Név:</label>
<input type="text" id="nev" name="nev">
<label for="email">E-mail:</label>
<input type="email" id="email" name="email">
<button type="submit">Küldés</button>
</form>
<!-- Jó: Interaktív elemek természetes fókusz sorrenddel -->
<div class="mukodok">
<button type="button">Szerkesztés</button>
<button type="button">Törlés</button>
<a href="/reszletek">Részletek</a>
</div>
Az alapértelmezett böngésző fókusz körvonal használata gyakran elegendő és konzisztens. A böngészők beépített fókusz stílusai megfelelnek az akadálymentességi követelményeknek.
2. Egyéni fókusz stílusok nagy kontraszttal
<!-- Jó: Egyéni gombok látható fókusz stílussal -->
<button class="primary-button">Főművelet</button>
<button class="secondary-button">Másodlagos művelet</button>
<button class="danger-button">Törlés</button>
<style>
/* Alapértelmezett gomb stílusok */
.primary-button {
background: #0066cc;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
}
.secondary-button {
background: #6c757d;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
}
.danger-button {
background: #dc3545;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
}
/* Jó: Nagy kontrasztú fókusz stílusok */
.primary-button:focus {
outline: 3px solid #ffbf47; /* Narancssárga körvonal */
outline-offset: 2px;
box-shadow: 0 0 0 1px #0066cc; /* Belső árnyék */
}
.secondary-button:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
box-shadow: 0 0 0 1px #6c757d;
}
.danger-button:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
box-shadow: 0 0 0 1px #dc3545;
}
/* Jó: Linkek egyéni fókusz stílusa */
a:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
background-color: #e6f3ff;
text-decoration: none;
}
/* Jó: Űrlap elemek egyéni fókusza */
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
textarea:focus {
outline: 2px solid #0066cc;
outline-offset: 1px;
border-color: #0066cc;
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}
select:focus {
outline: 2px solid #0066cc;
outline-offset: 1px;
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}
/* Jó: Checkbox és radio egyéni fókusza */
input[type="checkbox"]:focus,
input[type="radio"]:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
</style>
Ha felülírjuk az alapértelmezett körvonalat, biztosítani kell, hogy látható, nagy kontrasztú stílust alkalmazzunk. A narancssárga, vagy kék színek jól láthatók a legtöbb háttéren.
3. Fókusz egyéni komponenseken
<!-- Jó: Div elemek gombként, tabindex és fókusz stílussal -->
<div role="button" tabindex="0" class="custom-button" onclick="mukodes()">
Egyéni gomb
</div>
<div role="button" tabindex="0" class="icon-button" onclick="bezaras()">
<span aria-hidden="true">×</span>
<span class="sr-only">Bezárás</span>
</div>
<!-- Jó: Egyéni dropdown/accordion komponens -->
<div class="dropdown">
<button type="button"
class="dropdown-toggle"
aria-expanded="false"
aria-haspopup="true">
Menü megnyitása
</button>
<ul class="dropdown-menu" role="menu">
<li role="none">
<a href="/profil" role="menuitem">Profil</a>
</li>
<li role="none">
<a href="/beallitasok" role="menuitem">Beállítások</a>
</li>
<li role="none">
<button type="button" role="menuitem" onclick="kijelentkezes()">
Kijelentkezés
</button>
</li>
</ul>
</div>
<!-- Jó: Tab komponens -->
<div class="tabs" role="tablist">
<button type="button"
role="tab"
aria-selected="true"
aria-controls="tab1-panel"
id="tab1">
Áttekintés
</button>
<button type="button"
role="tab"
aria-selected="false"
aria-controls="tab2-panel"
id="tab2">
Részletek
</button>
<button type="button"
role="tab"
aria-selected="false"
aria-controls="tab3-panel"
id="tab3">
Értékelések
</button>
</div>
<style>
/* Egyéni gomb komponens fókusza */
.custom-button {
background: #28a745;
color: white;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
display: inline-block;
user-select: none;
}
.custom-button:focus {
outline: none; /* Alapértelmezett eltávolítása */
box-shadow: 0 0 0 3px #ffbf47; /* Sárga fényudvar */
background: #218838; /* Kissé sötétebb háttér */
}
/* Ikon gomb fókusza */
.icon-button {
background: #6c757d;
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
font-weight: bold;
}
.icon-button:focus {
outline: none;
box-shadow: 0 0 0 3px #ffbf47;
background: #5a6268;
}
/* Dropdown komponens fókusza */
.dropdown-toggle:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
box-shadow: 0 0 0 1px #fff, 0 0 0 3px #0066cc;
}
.dropdown-menu a:focus,
.dropdown-menu button:focus {
outline: none;
background-color: #0066cc;
color: white;
}
/* Tab komponens fókusza */
.tabs button[role="tab"]:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
z-index: 1;
position: relative;
}
/* Screen reader only szöveg */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>
<script>
// Billentyűzet támogatás egyéni gombokhoz
document.querySelectorAll('[role="button"]').forEach(button => {
button.addEventListener('keydown', function(e) {
// Enter vagy Space billentyű kezelése
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.click();
}
});
});
</script>
Egyéni widgetek esetén (pl. div elemek gombként) add hozzá a tabindex=”0″-t és látható fókusz stílusokat. A JavaScript biztosítja a billentyűzet funkcionalitást.
4. Fókusz láthatóság megőrzése animációk során
<!-- Jó: Animált gombok fókusz megőrzéssel -->
<button class="animated-button">Hover és Focus animáció</button>
<button class="pulse-button">Pulzáló gomb</button>
<button class="loading-button" onclick="loadingStart(this)">
<span class="button-text">Betöltés indítása</span>
<span class="loading-spinner" style="display: none;">⏳</span>
</button>
<!-- Jó: Accordions fókusz megtartással -->
<div class="accordion">
<button type="button"
class="accordion-header"
aria-expanded="false"
aria-controls="accordion-content-1">
GYIK - Gyakori kérdések
</button>
<div id="accordion-content-1" class="accordion-content" hidden>
<p>Itt találod a leggyakrabban feltett kérdéseket...</p>
</div>
</div>
<style>
/* Animált gomb, fókusz megőrzéssel */
.animated-button {
background: #007bff;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
transition: all 0.3s ease;
cursor: pointer;
}
.animated-button:hover {
background: #0056b3;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
/* Jó: Fókusz látható marad animáció során */
.animated-button:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
/* Animáció NEM rejti el a fókuszt */
}
.animated-button:focus:hover {
/* Hover és focus kombinálva */
outline: 3px solid #ffbf47;
outline-offset: 2px;
background: #0056b3;
transform: translateY(-2px);
}
/* Pulzáló animáció fókusz megtartással */
.pulse-button {
background: #28a745;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
animation: pulse 2s infinite;
cursor: pointer;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.pulse-button:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
/* Animáció nem befolyásolja a fókusz láthatóságát */
}
/* Loading gomb állapotok */
.loading-button {
background: #6c757d;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
position: relative;
}
.loading-button.loading {
pointer-events: none;
opacity: 0.7;
}
.loading-button:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
}
/* Jó: Loading állapotban is látható a fókusz */
.loading-button.loading:focus {
outline: 3px solid #ffbf47;
outline-offset: 2px;
}
/* Accordion fókusz stílusok */
.accordion-header {
width: 100%;
background: #f8f9fa;
border: 1px solid #dee2e6;
padding: 15px;
text-align: left;
cursor: pointer;
transition: background-color 0.3s ease;
}
.accordion-header:hover {
background: #e9ecef;
}
.accordion-header:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
background: #e9ecef;
/* Fókusz látható expansion során is */
}
.accordion-content {
border: 1px solid #dee2e6;
border-top: none;
padding: 15px;
background: white;
}
/* Smooth animációk fókusz megtartással */
.accordion-content {
overflow: hidden;
transition: max-height 0.3s ease;
}
.accordion-content[hidden] {
max-height: 0;
padding-top: 0;
padding-bottom: 0;
}
.accordion-content:not([hidden]) {
max-height: 500px;
}
</style>
<script>
function loadingStart(button) {
// Fókusz megtartása loading állapotban
const buttonText = button.querySelector('.button-text');
const spinner = button.querySelector('.loading-spinner');
button.classList.add('loading');
buttonText.style.display = 'none';
spinner.style.display = 'inline';
// Fókusz megmarad az elemen
button.setAttribute('aria-busy', 'true');
setTimeout(() => {
button.classList.remove('loading');
buttonText.style.display = 'inline';
spinner.style.display = 'none';
button.removeAttribute('aria-busy');
// Fókusz még mindig az elemen van
}, 3000);
}
// Accordion funkcionality
document.querySelectorAll('.accordion-header').forEach(header => {
header.addEventListener('click', function() {
const content = document.getElementById(this.getAttribute('aria-controls'));
const isExpanded = this.getAttribute('aria-expanded') === 'true';
this.setAttribute('aria-expanded', !isExpanded);
content.hidden = isExpanded;
// Fókusz megmarad a headeren az animáció során
});
});
</script>
Kerüld a fókusz jelző eltávolítását, vagy elrejtését átmenetek vagy animációk során. A fókusz mindig látható maradjon, még betöltési vagy expandáló állapotokban is.
Helytelen megoldás
Fókusz körvonal eltávolítása helyettesítés nélkül
<!-- Rossz: Fókusz eltávolítása minden elemről -->
<style>
a:focus,
button:focus,
input:focus {
outline: none; /* Rossz: eltávolítja a vizuális fókuszt */
}
/* Vagy általános reset */
* {
outline: none; /* Nagyon rossz: minden fókusz eltűnik */
}
*:focus {
outline: 0; /* Ugyanilyen rossz */
}
</style>
Probléma: A fókusz körvonal eltávolítása anélkül, hogy valami más helyettesítené, lehetetlenné teszi a billentyűzetes felhasználók számára a navigációt.
Alacsony kontrasztú fókusz stílusok
<!-- Rossz: Gyenge kontrasztú fókusz stílusok -->
<style>
button:focus {
outline: 1px solid #ccc; /* Túl halvány */
}
.light-button:focus {
outline: 1px solid #f0f0f0; /* Szinte láthatatlan */
background: #fafafa; /* Alig látható változás */
}
a:focus {
color: #ddd; /* Gyenge szín kontrast */
text-decoration: underline;
}
input:focus {
border: 1px solid #e0e0e0; /* Alig különbözik a normál állapottól */
}
</style>
Probléma: A fókusz jelzőnek ki kell tűnnie a háttérből. A halvány színek nem biztosítanak elegendő kontrasztot.
Nem szabványos interaktív elemek billentyűzet fókusz nélkül
<!-- Rossz: Div elemek gombként tabindex nélkül -->
<div class="clickable" onclick="action()">Kattints rám</div>
<span class="button-like" onclick="submit()">Küldés</span>
<!-- Rossz: Egyéni navigáció billentyűzet támogatás nélkül -->
<div class="menu-item" onmouseover="showSubmenu()">Menü</div>
<div class="carousel-button" onclick="nextSlide()">Következő</div>
<!-- Rossz: Hamis linkek -->
<a href="#" onclick="openModal()">Modal megnyitása</a>
<a href="javascript:void(0)" onclick="toggle()">Váltás</a>
Probléma: A div vagy span elemek használata gombként, de tabindex nélkül nem teszi őket billentyűzettel elérhetővé. A hamis linkek (# vagy javascript:) zavaróak.
Fókusz elrejtése egér interakció miatt
<!-- Rossz: Fókusz elrejtése minden esetben -->
<style>
/* Rossz megközelítés: mindenhol elrejti a fókuszt */
.no-focus-outline:focus {
outline: none;
}
button:active {
outline: none; /* Rossz: aktív állapotban is kell a fókusz */
}
/* Rossz: CSS-only megoldás ami elrejti a fókuszt */
.button:not(:focus-visible) {
outline: none; /* Nem minden böngésző támogatja */
}
</style>
<script>
// Rossz: Minden click után fókusz eltávolítása
document.addEventListener('click', function(e) {
e.target.blur(); // Rossz: billentyűzetes felhasználókat is érint
});
// Rossz: Fókusz elrejtése mouseover-rel
document.addEventListener('mouseover', function(e) {
if (e.target.matches('button, a, input')) {
e.target.style.outline = 'none'; // Rossz: billentyűzet fókusz is eltűnik
}
});
</script>
Probléma: A fókusz elrejtése egér interakció alapján gyakran a billentyűzetes felhasználókat is érinti. A :focus-visible használata jobb, de támogatást igényel.
Dinamikus tartalom fókusz kezelés nélkül
<!-- Rossz: Modal megnyitása fókusz kezelés nélkül -->
<script>
function rossModalMegnyitas() {
const modal = document.getElementById('modal');
modal.style.display = 'block';
// Rossz: nem állítja át a fókuszt a modalra
// A billentyűzetes felhasználók továbbra is a háttérben navigálnak
}
function rossModalBezaras() {
const modal = document.getElementById('modal');
modal.style.display = 'none';
// Rossz: nem állítja vissza a fókuszt az eredeti elemre
}
// Rossz: Dinamikus tartalom hozzáadása fókusz nélkül
function rossUjTartalomHozzaadas() {
const container = document.getElementById('content');
container.innerHTML = `
<h2>Új tartalom</h2>
<button>Új gomb</button>
`;
// Rossz: nem értesíti a felhasználót a változásról
// Nem irányítja a fókuszt az új tartalomra
}
</script>
<!-- Rossz: Tab komponens rossz fókusz kezeléssel -->
<script>
function rossTabVáltas(tabId) {
// Minden tab elrejtése
document.querySelectorAll('.tab-content').forEach(content => {
content.style.display = 'none';
});
// Kiválasztott tab megjelenítése
document.getElementById(tabId).style.display = 'block';
// Rossz: nem kezeli a fókuszt
// A billentyűzetes felhasználók nem tudják, hogy váltott a tartalom
}
</script>
Probléma: Dinamikus tartalom megjelenésekor, vagy modal ablakok nyitásakor a fókusz kezelése kritikus. A fókusz megfelelő áthelyezése nélkül a billentyűzetes felhasználók elvesznek.
Fókusz csapdák és korlátlan fókusz mozgás
<!-- Rossz: Modal fókusz csapda nélkül -->
<div class="modal" style="display: block;">
<div class="modal-content">
<h2>Modal cím</h2>
<button>OK</button>
<button>Mégse</button>
</div>
</div>
<!-- Rossz: A fókusz ki tud jutni a modalból a háttér elemekre -->
<script>
// Rossz: Végtelen fókusz hurok egyéni komponensben
function rossDropdownNavigation(event) {
const items = dropdown.querySelectorAll('a');
let currentIndex = Array.from(items).indexOf(event.target);
if (event.key === 'ArrowDown') {
currentIndex++;
// Rossz: nem ellenőrzi a határokat
items[currentIndex].focus(); // Hiba ha currentIndex >= items.length
}
}
// Rossz: Fókusz "ugrik" véletlenszerűen
function rossRandomFocus() {
const buttons = document.querySelectorAll('button');
const randomButton = buttons[Math.floor(Math.random() * buttons.length)];
randomButton.focus(); // Váratlan fókusz mozgás
}
</script>
Probléma: A modal ablakokban a fókusz fixálás hiánya lehetővé teszi, hogy a felhasználók a háttér tartalmára navigáljanak. A váratlan fókusz mozgások megzavarják a navigációt.
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!