2.5.1 - Mutatógesztusok
Röviden a szabványpontról
A WCAG 2.5.1 (Pointer Gestures) előírja, hogy minden funkcionalitás, amely többpontos vagy útvonal-alapú gesztusokat használ (mint csípés, húzás vagy forgatás), egypontos bevitellel is működtethető legyen (például egyszerű érintés vagy kattintás). Ez azt jelenti, hogy a felhasználókat nem szabad összetett gesztusok használatára kényszeríteni, a tartalom, vagy vezérlők kezeléséhez.
Mire vonatkozik: Minden interaktív elemre vagy funkcionalitásra egy weboldalon vagy alkalmazásban, amely többujjas vagy összetett mozdulatokat igényel.
Cél: Biztosítani, hogy a korlátozott mozgási képességekkel rendelkező vagy segítő technológiákat használó felhasználók:
- gond nélkül működtethessék az interaktív komponenseket
- Ne kelljen összetett gesztusokat végrehajtaniuk
- Alternatív módszerekkel érhessék el ugyanazt a funkcionalitást
- Egyszerű érintéssel vagy kattintással is használhassák a felületet
Kiket érint
Elsődleges felhasználók: Mozgáskorlátozottak vagy korlátozott kézügyességgel rendelkezők, akik nem tudnak megbízhatóan többujjas vagy összetett gesztusokat végrehajtani. Ide tartoznak a remegéssel, bénulással élők vagy stylus-t és egykapcsolós beviteli eszközt használók.
Másodlagos előnyök: A gesztusok egyszerűsítése segít a korlátozott beviteli képességekkel rendelkező eszközöket használóknak és olyan helyzetekben, ahol a többujjas gesztusok kényelmetlenek (pl. egykezes eszközhasználat).
Tesztelés
- Manuális gesztus tesztelés: Azonosítsd az összes többujjas vagy útvonal-alapú gesztust igénylő UI elemet. Próbáld meg ugyanazt a funkciót egypontos bevitellel (kattintás, érintés vagy billentyűzet) végrehajtani
- Segítő technológia tesztelés: Használj segítő eszközöket (kapcsoló eszközök, stylus, billentyűzetes navigáció) a gesztus-alapú vezérlők működtetéséhez
- Felhasználó szimuláció: Használd a böngésző fejlesztői eszközeit vagy eszköz szimulátorokat egypontos bevitel szimulálására és a UI funkcionalitás tesztelésére
- Kód áttekintés: Vizsgáld meg a JavaScript eseménykezelőket vagy érintési esemény figyelőket, hogy léteznek-e alternatívák az összetett gesztusokhoz
- Felhasználói visszajelzés: Gyűjts visszajelzéseket mozgáskorlátozottaktól, hogy megerősítsd a könnyű használhatóságot összetett gesztusok nélkül
Jó megoldások
1. Húzás törléshez alternatív gombbal
<!-- Jó: Látható törlés gomb a húzás gesztus mellett -->
<div class="lista-container">
<div class="lista-elem" tabindex="0" data-id="1">
<span class="elem-tartalom">1. lista elem</span>
<button class="torles-gomb"
aria-label="1. lista elem törlése"
onclick="elemTorles(1)">
🗑️ Törlés
</button>
</div>
<div class="lista-elem" tabindex="0" data-id="2">
<span class="elem-tartalom">2. lista elem</span>
<button class="torles-gomb"
aria-label="2. lista elem törlése"
onclick="elemTorles(2)">
🗑️ Törlés
</button>
</div>
<div class="lista-elem" tabindex="0" data-id="3">
<span class="elem-tartalom">3. lista elem</span>
<button class="torles-gomb"
aria-label="3. lista elem törlése"
onclick="elemTorles(3)">
🗑️ Törlés
</button>
</div>
</div>
<style>
.lista-container {
max-width: 400px;
margin: 20px auto;
}
.lista-elem {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 8px;
background: white;
/* Támogatja mind a húzást, mind a gomb kattintást */
touch-action: pan-x pan-y; /* Engedélyezi a húzást */
}
.lista-elem:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
.elem-tartalom {
flex: 1;
padding-right: 10px;
}
.torles-gomb {
background: #dc3545;
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.torles-gomb:hover {
background: #c82333;
}
.torles-gomb:focus {
outline: 2px solid #fff;
outline-offset: 2px;
box-shadow: 0 0 0 4px #dc3545;
}
/* Húzás animáció opcionális */
.lista-elem.huzva {
transform: translateX(-100px);
transition: transform 0.3s ease;
}
</style>
<script>
// Egypontos alternatíva: gomb kattintás
function elemTorles(id) {
const elem = document.querySelector(`[data-id="${id}"]`);
if (elem && confirm('Biztosan törlöd ezt az elemet?')) {
elem.remove();
}
}
// Opcionális: húzás gesztus támogatása (mint plusz funkció)
document.querySelectorAll('.lista-elem').forEach(elem => {
let startX = 0;
let currentX = 0;
let isSwipeing = false;
// Érintés kezdete
elem.addEventListener('touchstart', function(e) {
startX = e.touches[0].clientX;
isSwipeing = true;
});
// Érintés mozgatása
elem.addEventListener('touchmove', function(e) {
if (!isSwipeing) return;
currentX = e.touches[0].clientX;
const diffX = startX - currentX;
if (diffX > 0) {
this.style.transform = `translateX(-${Math.min(diffX, 100)}px)`;
}
});
// Érintés vége
elem.addEventListener('touchend', function(e) {
if (!isSwipeing) return;
isSwipeing = false;
const diffX = startX - currentX;
if (diffX > 50) {
// Húzás elegendő volt
const id = this.getAttribute('data-id');
elemTorles(id);
} else {
// Vissza eredeti pozícióba
this.style.transform = 'translateX(0)';
}
});
});
</script>
A felhasználók, akik nem tudnak húzni, továbbra is törölhetik az elemet a gombra kattintva. A húzás csak kiegészítő funkcióként szolgál.
2. Csípés nagyításhoz és nagyítás vezérlőkkel
<!-- Jó: Nagyítás gombok a csípés gesztus mellett -->
<div class="nagyithato-container">
<div class="kepgaleria">
<img id="nagyithato-kep"
src="/images/pelda-kep.jpg"
alt="Nagyítható példa kép"
style="width: 100%; max-width: 500px; transform-origin: center;">
</div>
<div class="nagyitas-vezerlok">
<button id="kicsinyites"
aria-label="Kép kicsinyítése"
onclick="zoomOut()">
🔍➖ Kicsinyítés
</button>
<span id="nagyitas-szint" aria-live="polite">100%</span>
<button id="nagyitas"
aria-label="Kép nagyítása"
onclick="zoomIn()">
🔍➕ Nagyítás
</button>
<button id="eredeti-meret"
aria-label="Eredeti méret visszaállítása"
onclick="resetZoom()">
🔄 Eredeti méret
</button>
</div>
<div class="billentyuzet-help">
<small>
Billentyűzet: + nagyítás, - kicsinyítés, 0 eredeti méret
</small>
</div>
</div>
<style>
.nagyithato-container {
max-width: 600px;
margin: 20px auto;
text-align: center;
}
.kepgaleria {
border: 2px solid #ddd;
border-radius: 8px;
padding: 10px;
margin-bottom: 15px;
overflow: auto;
/* Támogatja mind a csípést, mind a gombokat */
touch-action: manipulation; /* Engedélyezi a csípés gesztust */
}
.nagyitas-vezerlok {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.nagyitas-vezerlok button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.nagyitas-vezerlok button:hover {
background: #0056b3;
}
.nagyitas-vezerlok button:focus {
outline: 2px solid #ffc107;
outline-offset: 2px;
}
.nagyitas-vezerlok button:disabled {
background: #6c757d;
cursor: not-allowed;
}
#nagyitas-szint {
background: #f8f9fa;
padding: 8px 12px;
border-radius: 4px;
border: 1px solid #dee2e6;
font-weight: bold;
min-width: 60px;
}
.billentyuzet-help {
color: #6c757d;
margin-top: 10px;
}
</style>
<script>
let aktualisNagyitas = 1; // 100%
const minNagyitas = 0.5; // 50%
const maxNagyitas = 3; // 300%
const nagyitasLepes = 0.25; // 25% lépések
// Egypontos alternatívák: gombok
function zoomIn() {
if (aktualisNagyitas < maxNagyitas) {
aktualisNagyitas += nagyitasLepes;
updateZoom();
}
}
function zoomOut() {
if (aktualisNagyitas > minNagyitas) {
aktualisNagyitas -= nagyitasLepes;
updateZoom();
}
}
function resetZoom() {
aktualisNagyitas = 1;
updateZoom();
}
function updateZoom() {
const kep = document.getElementById('nagyithato-kep');
const szintElem = document.getElementById('nagyitas-szint');
kep.style.transform = `scale(${aktualisNagyitas})`;
szintElem.textContent = `${Math.round(aktualisNagyitas * 100)}%`;
// Gombok állapotának frissítése
document.getElementById('kicsinyites').disabled = aktualisNagyitas <= minNagyitas;
document.getElementById('nagyitas').disabled = aktualisNagyitas >= maxNagyitas;
}
// Billentyűzet támogatás
document.addEventListener('keydown', function(e) {
if (e.target.closest('.nagyithato-container')) {
switch(e.key) {
case '+':
case '=':
e.preventDefault();
zoomIn();
break;
case '-':
e.preventDefault();
zoomOut();
break;
case '0':
e.preventDefault();
resetZoom();
break;
}
}
});
// Opcionális: csípés gesztus támogatása (plusz funkció)
const kep = document.getElementById('nagyithato-kep');
let kezdetiTavolsag = 0;
let kezdetiNagyitas = 1;
kep.addEventListener('touchstart', function(e) {
if (e.touches.length === 2) {
const touch1 = e.touches[0];
const touch2 = e.touches[1];
kezdetiTavolsag = Math.hypot(
touch2.clientX - touch1.clientX,
touch2.clientY - touch1.clientY
);
kezdetiNagyitas = aktualisNagyitas;
}
});
kep.addEventListener('touchmove', function(e) {
if (e.touches.length === 2) {
e.preventDefault();
const touch1 = e.touches[0];
const touch2 = e.touches[1];
const jelenlegi_tavolsag = Math.hypot(
touch2.clientX - touch1.clientX,
touch2.clientY - touch1.clientY
);
const arany = jelenlegi_tavolsag / kezdetiTavolsag;
const ujNagyitas = kezdetiNagyitas * arany;
aktualisNagyitas = Math.min(Math.max(ujNagyitas, minNagyitas), maxNagyitas);
updateZoom();
}
});
// Kezdeti állapot beállítása
updateZoom();
</script>
A felhasználók gombokkal, vagy billentyűzettel is nagyíthatnak a csípés gesztus helyett. A csípés csak kiegészítő lehetőségként szolgál.
3. Forgatás gesztus és forgatás gombokkal
<!-- Jó: Forgatás gombok a forgatás gesztus mellett -->
<div class="forgathato-container">
<div class="kep-kontener">
<img id="forgathato-kep"
src="/images/forgathato-kep.jpg"
alt="Forgatható kép"
tabindex="0"
aria-describedby="forgatas-info"
style="transition: transform 0.3s ease;">
</div>
<div id="forgatas-info" class="sr-only">
Forgatható kép. Használd a forgatás gombokat vagy a nyíl billentyűket.
</div>
<div class="forgatas-vezerlok">
<button id="balra-forgatas"
aria-label="Kép forgatása balra 90 fokkal"
onclick="rotateLeft()">
↺ Balra forgatás
</button>
<span id="forgatas-szog" aria-live="polite">0°</span>
<button id="jobbra-forgatas"
aria-label="Kép forgatása jobbra 90 fokkal"
onclick="rotateRight()">
↻ Jobbra forgatás
</button>
<button id="forgatas-reset"
aria-label="Forgatás visszaállítása eredeti pozícióba"
onclick="resetRotation()">
🔄 Eredeti pozíció
</button>
</div>
<div class="billentyuzet-help">
<small>
Billentyűzet: ← balra, → jobbra, ↑ eredeti pozíció
</small>
</div>
</div>
<!-- Jó: Térkép forgatás navigációs alkalmazásban -->
<div class="terkep-container">
<div class="terkep-wrapper">
<div id="terkep"
class="terkep"
tabindex="0"
aria-label="Interaktív térkép"
aria-describedby="terkep-info">
<!-- Térkép tartalom -->
<div class="terkep-tartalom">
📍 Budapest<br>
🏢 Irodák<br>
🚗 Parkolók
</div>
</div>
<div id="terkep-info" class="sr-only">
Térkép forgatható az iránytű gombokkal vagy a Shift + nyíl billentyűkkel.
</div>
</div>
<div class="terkep-vezerlok">
<div class="iranytu">
<button class="iranytu-gomb iranytu-eszak"
aria-label="Térkép forgatása északra"
onclick="mapRotateToNorth()">
⬆️ É
</button>
<button class="iranytu-gomb iranytu-kelet"
aria-label="Térkép forgatása keletre"
onclick="mapRotateToEast()">
➡️ K
</button>
<button class="iranytu-gomb iranytu-del"
aria-label="Térkép forgatása délre"
onclick="mapRotateToSouth()">
⬇️ D
</button>
<button class="iranytu-gomb iranytu-nyugat"
aria-label="Térkép forgatása nyugatra"
onclick="mapRotateToWest()">
⬅️ Ny
</button>
</div>
<button id="auto-irany"
aria-label="Automatikus irány követés"
onclick="autoOrientation()">
🧭 Auto irány
</button>
</div>
</div>
<style>
.forgathato-container, .terkep-container {
max-width: 400px;
margin: 20px auto;
text-align: center;
}
.kep-kontener, .terkep-wrapper {
border: 2px solid #ddd;
border-radius: 8px;
padding: 20px;
margin-bottom: 15px;
background: #f8f9fa;
/* Támogatja mind a forgatást, mind a gombokat */
}
#forgathato-kep {
max-width: 100%;
height: auto;
border-radius: 4px;
/* Forgatás gesztus támogatása opcionális */
touch-action: manipulation;
}
#forgathato-kep:focus {
outline: 2px solid #007bff;
outline-offset: 4px;
}
.forgatas-vezerlok, .terkep-vezerlok {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-bottom: 10px;
flex-wrap: wrap;
}
.forgatas-vezerlok button, .terkep-vezerlok button {
background: #28a745;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.forgatas-vezerlok button:hover, .terkep-vezerlok button:hover {
background: #218838;
}
.forgatas-vezerlok button:focus, .terkep-vezerlok button:focus {
outline: 2px solid #ffc107;
outline-offset: 2px;
}
#forgatas-szog {
background: #e9ecef;
padding: 8px 12px;
border-radius: 4px;
border: 1px solid #ced4da;
font-weight: bold;
min-width: 50px;
}
/* Térkép specifikus stílusok */
.terkep {
width: 200px;
height: 200px;
background: #e3f2fd;
border: 2px solid #1976d2;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
transition: transform 0.5s ease;
touch-action: manipulation; /* Forgatás gesztus támogatása */
}
.terkep:focus {
outline: 2px solid #ff9800;
outline-offset: 4px;
}
.terkep-tartalom {
text-align: center;
font-size: 14px;
line-height: 1.5;
}
.iranytu {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
gap: 2px;
margin: 0 20px;
}
.iranytu-gomb {
width: 40px;
height: 40px;
font-size: 12px;
padding: 2px;
}
.iranytu-eszak { grid-column: 2; grid-row: 1; }
.iranytu-kelet { grid-column: 3; grid-row: 2; }
.iranytu-del { grid-column: 2; grid-row: 3; }
.iranytu-nyugat { grid-column: 1; grid-row: 2; }
.billentyuzet-help {
color: #6c757d;
margin-top: 10px;
}
.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>
// Kép forgatás változók
let aktualisSzog = 0; // fokokban
// Egypontos alternatívák: gombok
function rotateLeft() {
aktualisSzog -= 90;
if (aktualisSzog < 0) aktualisSzog += 360;
updateRotation();
}
function rotateRight() {
aktualisSzog += 90;
if (aktualisSzog >= 360) aktualisSzog -= 360;
updateRotation();
}
function resetRotation() {
aktualisSzog = 0;
updateRotation();
}
function updateRotation() {
const kep = document.getElementById('forgathato-kep');
const szogElem = document.getElementById('forgatas-szog');
kep.style.transform = `rotate(${aktualisSzog}deg)`;
szogElem.textContent = `${aktualisSzog}°`;
}
// Térkép forgatás változók
let terkepSzog = 0; // 0=észak, 90=kelet, 180=dél, 270=nyugat
function mapRotateToNorth() { terkepSzog = 0; updateMapRotation(); }
function mapRotateToEast() { terkepSzog = 90; updateMapRotation(); }
function mapRotateToSouth() { terkepSzog = 180; updateMapRotation(); }
function mapRotateToWest() { terkepSzog = 270; updateMapRotation(); }
function autoOrientation() {
// Szimulálja az automatikus irány beállítást
terkepSzog = 0;
updateMapRotation();
alert('Automatikus irány bekapcsolva - térkép mindig észak felé mutat');
}
function updateMapRotation() {
const terkep = document.getElementById('terkep');
terkep.style.transform = `rotate(${terkepSzog}deg)`;
}
// Billentyűzet támogatás
document.addEventListener('keydown', function(e) {
// Kép forgatás billentyűzet támogatás
if (e.target.id === 'forgathato-kep') {
switch(e.key) {
case 'ArrowLeft':
e.preventDefault();
rotateLeft();
break;
case 'ArrowRight':
e.preventDefault();
rotateRight();
break;
case 'ArrowUp':
e.preventDefault();
resetRotation();
break;
}
}
// Térkép forgatás billentyűzet támogatás (Shift + nyíl)
if (e.target.id === 'terkep' && e.shiftKey) {
switch(e.key) {
case 'ArrowUp':
e.preventDefault();
mapRotateToNorth();
break;
case 'ArrowRight':
e.preventDefault();
mapRotateToEast();
break;
case 'ArrowDown':
e.preventDefault();
mapRotateToSouth();
break;
case 'ArrowLeft':
e.preventDefault();
mapRotateToWest();
break;
}
}
});
// Kezdeti állapot
updateRotation();
updateMapRotation();
</script>
A forgatás elérhető gombokkal és billentyűzettel, így a forgatás gesztust nem alakalmazó felhasználók is használhatják. A gesztus támogatás csak kiegészítő funkció.
4. Karussel/slider navigáció többféle módon
<!-- Jó: Karussel több navigációs móddal -->
<div class="karussel-container">
<div class="karussel"
id="galeria-karussel"
role="region"
aria-label="Képgaléria"
aria-describedby="karussel-info">
<div id="karussel-info" class="sr-only">
Képgaléria navigáció: nyíl gombokkal, pontokkal, billentyűzettel vagy húzással.
</div>
<div class="karussel-wrapper">
<div class="karussel-slide aktiv" data-slide="0">
<img src="/images/slide1.jpg" alt="1. dia: Természet">
<h3>Természet</h3>
</div>
<div class="karussel-slide" data-slide="1">
<img src="/images/slide2.jpg" alt="2. dia: Építészet">
<h3>Építészet</h3>
</div>
<div class="karussel-slide" data-slide="2">
<img src="/images/slide3.jpg" alt="3. dia: Emberek">
<h3>Emberek</h3>
</div>
</div>
<!-- Nyíl navigáció (egypontos alternatíva) -->
<button class="karussel-nav karussel-prev"
aria-label="Előző dia"
onclick="prevSlide()">
‹
</button>
<button class="karussel-nav karussel-next"
aria-label="Következő dia"
onclick="nextSlide()">
›
</button>
</div>
<!-- Pont navigáció (egypontos alternatíva) -->
<div class="karussel-dots" role="tablist" aria-label="Dia választás">
<button class="dot aktiv"
role="tab"
aria-selected="true"
aria-controls="slide-0"
aria-label="1. dia megjelenítése"
onclick="goToSlide(0)"></button>
<button class="dot"
role="tab"
aria-selected="false"
aria-controls="slide-1"
aria-label="2. dia megjelenítése"
onclick="goToSlide(1)"></button>
<button class="dot"
role="tab"
aria-selected="false"
aria-controls="slide-2"
aria-label="3. dia megjelenítése"
onclick="goToSlide(2)"></button>
</div>
<!-- Lejátszás vezérlők -->
<div class="karussel-controls">
<button id="play-pause"
aria-label="Automatikus lejátszás indítása"
onclick="toggleAutoplay()">
▶️ Lejátszás
</button>
<button aria-label="Karussel visszaállítása első diára"
onclick="goToSlide(0)">
⏮️ Első dia
</button>
</div>
<div class="billentyuzet-help">
<small>
Billentyűzet: ← előző, → következő, Home első, End utolsó, Space lejátszás
</small>
</div>
</div>
<style>
.karussel-container {
max-width: 600px;
margin: 20px auto;
}
.karussel {
position: relative;
background: #f8f9fa;
border-radius: 8px;
overflow: hidden;
/* Támogatja mind a húzást, mind a gombokat */
touch-action: pan-y pinch-zoom; /* Engedélyezi vízszintes húzást */
}
.karussel-wrapper {
display: flex;
transition: transform 0.3s ease;
width: 300%; /* 3 dia = 300% */
}
.karussel-slide {
width: 33.333%; /* 100% / 3 dia */
text-align: center;
padding: 20px;
}
.karussel-slide.aktiv {
/* Aktív dia stílusok */
}
.karussel-slide img {
width: 100%;
max-width: 300px;
height: 200px;
object-fit: cover;
border-radius: 4px;
}
.karussel-slide h3 {
margin: 10px 0 0 0;
color: #333;
}
/* Nyíl navigáció */
.karussel-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
width: 40px;
height: 40px;
font-size: 24px;
cursor: pointer;
border-radius: 50%;
transition: background 0.3s ease;
}
.karussel-nav:hover {
background: rgba(0, 0, 0, 0.9);
}
.karussel-nav:focus {
outline: 2px solid #ffc107;
outline-offset: 2px;
}
.karussel-prev {
left: 10px;
}
.karussel-next {
right: 10px;
}
.karussel-nav:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Pont navigáció */
.karussel-dots {
text-align: center;
margin: 15px 0;
}
.dot {
background: #ccc;
border: none;
width: 12px;
height: 12px;
border-radius: 50%;
margin: 0 5px;
cursor: pointer;
transition: background 0.3s ease;
}
.dot:hover {
background: #999;
}
.dot:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
.dot.aktiv {
background: #007bff;
}
/* Vezérlők */
.karussel-controls {
text-align: center;
margin-bottom: 10px;
}
.karussel-controls button {
background: #6c757d;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
margin: 0 5px;
cursor: pointer;
}
.karussel-controls button:hover {
background: #5a6268;
}
.karussel-controls button:focus {
outline: 2px solid #ffc107;
outline-offset: 2px;
}
.billentyuzet-help {
text-align: center;
color: #6c757d;
margin-top: 10px;
}
</style>
<script>
let aktivisDia = 0;
const osszDia = 3;
let autoplayInterval = null;
let isAutoplayActive = false;
// Egypontos alternatívák: gombok és billentyűzet
function nextSlide() {
aktivisDia = (aktivisDia + 1) % osszDia;
updateSlide();
}
function prevSlide() {
aktivisDia = (aktivisDia - 1 + osszDia) % osszDia;
updateSlide();
}
function goToSlide(slideIndex) {
aktivisDia = slideIndex;
updateSlide();
}
function updateSlide() {
const wrapper = document.querySelector('.karussel-wrapper');
const dots = document.querySelectorAll('.dot');
const slides = document.querySelectorAll('.karussel-slide');
// Dia mozgatása
wrapper.style.transform = `translateX(-${aktivisDia * 33.333}%)`;
// Aktív állapotok frissítése
dots.forEach((dot, index) => {
dot.classList.toggle('aktiv', index === aktivisDia);
dot.setAttribute('aria-selected', index === aktivisDia);
});
slides.forEach((slide, index) => {
slide.classList.toggle('aktiv', index === aktivisDia);
});
// Navigációs gombok állapota
const prevBtn = document.querySelector('.karussel-prev');
const nextBtn = document.querySelector('.karussel-next');
// Opcionális: első/utolsó dia esetén letiltás
// prevBtn.disabled = aktivisDia === 0;
// nextBtn.disabled = aktivisDia === osszDia - 1;
}
function toggleAutoplay() {
const playBtn = document.getElementById('play-pause');
if (isAutoplayActive) {
clearInterval(autoplayInterval);
playBtn.textContent = '▶️ Lejátszás';
playBtn.setAttribute('aria-label', 'Automatikus lejátszás indítása');
isAutoplayActive = false;
} else {
autoplayInterval = setInterval(nextSlide, 3000);
playBtn.textContent = '⏸️ Szünet';
playBtn.setAttribute('aria-label', 'Automatikus lejátszás megállítása');
isAutoplayActive = true;
}
}
// Billentyűzet támogatás
document.addEventListener('keydown', function(e) {
if (e.target.closest('.karussel-container')) {
switch(e.key) {
case 'ArrowLeft':
e.preventDefault();
prevSlide();
break;
case 'ArrowRight':
e.preventDefault();
nextSlide();
break;
case 'Home':
e.preventDefault();
goToSlide(0);
break;
case 'End':
e.preventDefault();
goToSlide(osszDia - 1);
break;
case ' ':
e.preventDefault();
toggleAutoplay();
break;
}
}
});
// Opcionális: húzás gesztus támogatása (plusz funkció)
let startX = 0;
let startY = 0;
let isSwipeing = false;
const karussel = document.querySelector('.karussel');
karussel.addEventListener('touchstart', function(e) {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
isSwipeing = true;
});
karussel.addEventListener('touchmove', function(e) {
if (!isSwipeing) return;
const currentX = e.touches[0].clientX;
const currentY = e.touches[0].clientY;
const diffX = Math.abs(currentX - startX);
const diffY = Math.abs(currentY - startY);
// Csak vízszintes húzás
if (diffX > diffY && diffX > 30) {
e.preventDefault();
}
});
karussel.addEventListener('touchend', function(e) {
if (!isSwipeing) return;
isSwipeing = false;
const endX = e.changedTouches[0].clientX;
const diffX = startX - endX;
if (Math.abs(diffX) > 50) {
if (diffX > 0) {
nextSlide(); // Balra húzás = következő
} else {
prevSlide(); // Jobbra húzás = előző
}
}
});
// Kezdeti állapot
updateSlide();
</script>
A karussel többféle navigációs módot biztosít: nyíl gombok, pont navigáció, billentyűzet és opcionálisan húzás gesztus. Minden felhasználó megtalálja a maga számára megfelelő módot.
Helytelen megoldások
Csak gesztus-alapú interakciók
<!-- Rossz: Karussel csak húzással működik -->
<div id="rossz-karussel" ontouchstart="handleSwipe(event)">
<div class="slide">1. dia</div>
<div class="slide">2. dia</div>
<div class="slide">3. dia</div>
</div>
<!-- Nincsenek gombok vagy billentyűzet alternatívák -->
<!-- Rossz: Csak csípés nagyítás -->
<img id="rossz-zoom" src="kep.jpg" alt="Kép">
<script>
// Rossz: csak többujjas gesztus támogatás
document.getElementById('rossz-zoom').addEventListener('gesturechange', function(e) {
this.style.transform = `scale(${e.scale})`;
// Nincs egypontos alternatíva
});
</script>
<!-- Rossz: Csak forgatás gesztus -->
<div id="rossz-forgatas" style="touch-action: none;">
Forgatható elem
</div>
<script>
// Rossz: csak összetett gesztus
let startAngle = 0;
document.getElementById('rossz-forgatas').addEventListener('touchstart', function(e) {
if (e.touches.length === 2) {
// Csak kétujjas forgatás támogatva
// Nincs egypontos alternatíva
}
});
</script>
Probléma: A felhasználók, akik nem tudnak húzni, csípni vagy forgatni, egyáltalán nem tudják használni ezeket a funkciókat.
Összetett gesztus visszaállítás nélkül
<!-- Rossz: Többérintéses gesztus egypontos visszaállítás nélkül -->
<div id="complex-gesture" style="width: 200px; height: 200px; background: #ccc;">
Összetett gesztus terület
</div>
<script>
// Rossz: csak többérintéses interakció
const elem = document.getElementById('complex-gesture');
elem.addEventListener('gesturechange', function(event) {
// Csak multi-touch gesztus kezelése
this.style.transform = `scale(${event.scale}) rotate(${event.rotation}deg)`;
// Nincs egypontos visszaállítás lehetőség
});
// Rossz: komplex útvonal gesztus
let path = [];
elem.addEventListener('touchmove', function(e) {
if (e.touches.length === 1) {
path.push({x: e.touches[0].clientX, y: e.touches[0].clientY});
// Csak összetett útvonal minták elismerése
if (isComplexPattern(path)) {
// Működés aktiválása
// Nincs egyszerű alternatíva
}
}
});
function isComplexPattern(path) {
// Csak összetett minták (pl. "Z" alakú mozgás)
return path.length > 10; // Túl összetett kritérium
}
</script>
Probléma: A funkcionalitás megtörik azok számára, akiknek nincs többérintéses beviteli lehetőségük.
Nem támogatott a billentyűzet vagy egypontos kezelés
<!-- Rossz: Interaktív elemek csak gesztusokra támaszkodva -->
<div class="gesture-only-interface">
<div class="swipeable-card" data-action="delete">
Húzd balra a törléshez
<!-- Nincs törlés gomb -->
</div>
<div class="pinchable-content">
Csípj a nagyításhoz
<!-- Nincsenek nagyítás gombok -->
</div>
<div class="rotatable-wheel">
Forgasd az értékek változtatásához
<!-- Nincs input mező vagy gombok -->
</div>
</div>
<!-- Rossz: Menü csak gesztussal nyitható -->
<div class="hidden-menu"
ontouchstart="menuOpen(event)"
style="display: none;">
<!-- Menü tartalom -->
</div>
<script>
// Rossz: csak gesztus alapú megnyitás
function menuOpen(e) {
if (e.touches.length === 3) {
// Csak három ujjas érintés
document.querySelector('.hidden-menu').style.display = 'block';
// Nincs gomb vagy billentyűzet alternatíva
}
}
// Rossz: képernyő szélén gesztusok
document.addEventListener('touchstart', function(e) {
const touch = e.touches[0];
// Csak szél gesztusok
if (touch.clientX < 20) {
// Baloldali szél gesztus
// Nincs alternatív aktiválási mód
}
if (touch.clientX > window.innerWidth - 20) {
// Jobboldali szél gesztus
// Szintén nincs alternatíva
}
});
</script>
Probléma: Az interaktív elemek, amelyek kizárólag többérintéses gesztusokra támaszkodnak, billentyűzet, vagy egér/egyérintéses alternatívák nélkül, kizárnak számos felhasználót.
Nehezen felismerhető vagy dokumentálatlan gesztusok
<!-- Rossz: Rejtett vagy nem intuitív gesztusok -->
<div class="secret-gestures" style="width: 300px; height: 200px; background: #f0f0f0;">
<p>Rejtett funkciók területe</p>
<!-- Nincs útmutatás a gesztusokhoz -->
</div>
<script>
// Rossz: összetett, nem intuitív gesztus kombinációk
const area = document.querySelector('.secret-gestures');
area.addEventListener('touchstart', function(e) {
// Rossz: túl specifikus gesztus követelmények
if (e.touches.length === 2) {
const touch1 = e.touches[0];
const touch2 = e.touches[1];
// Rossz: pontos pozíció követelmény
if (touch1.clientX < 100 && touch2.clientX > 200) {
// Csak ha az első érintés bal oldalon, második jobb oldalon
// Nincs alternatíva vagy útmutatás
secretFunction();
}
}
});
// Rossz: időzített gesztus szekvenciák
let gestureSequence = [];
let lastGestureTime = 0;
area.addEventListener('touchend', function(e) {
const now = Date.now();
// Rossz: időzített gesztus szekvencia
if (now - lastGestureTime < 500) {
gestureSequence.push('tap');
// Rossz: specifikus szekvencia követelmény
if (gestureSequence.join(',') === 'tap,tap,swipe,pinch') {
// Csak ha pontos szekvenciát követnek
// Nincs egyszerű alternatíva
advancedFunction();
}
} else {
gestureSequence = [];
}
lastGestureTime = now;
});
function secretFunction() {
alert('Rejtett funkció aktiválva!');
// Ezt a funkciót csak gesztussal lehet elérni
}
function advancedFunction() {
alert('Haladó funkció aktiválva!');
// Ez is csak összetett gesztus szekvenciával
}
</script>
Probléma: A rejtett, összetett, vagy nem dokumentált gesztusok akadálymentességi és használhatósági problémákat okoznak. Minden funkciónak elérhető alternatívával kell rendelkeznie.
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!