강력한 구조와 사용자 제어 기능을 제공하여 접근 가능한 캐러셀 위젯을 구현하세요.
- 구조 : 캐러셀에 시맨틱 구조를 사용하여 보조 기술의 적절한 기능을 지원합니다.
- 기능 : 캐러셀 항목을 표시하고 알리는 기능을 추가합니다.
- 애니메이션 : 항목 간에 전환 애니메이션을 추가하고 사용자가 중단했다가 다시 시작할 수 있도록 하세요.
- 스타일링 : 캐러셀의 스타일을 지정하여 모든 사람이 쉽게 사용할 수 있고 읽을 수 있도록 하세요.
예제 캐러셀의 전체 작동 예제와 전체 코드도 참조하세요.
캐러셀이란 무엇인가요?
캐러셀은 한 번에 하나씩 항목 모음을 표시합니다. "슬라이드쇼" 및 "슬라이더"라고도 합니다. 캐러셀의 일반적인 용도로는 뉴스 헤드라인 스크롤, 홈 페이지의 추천 기사, 이미지 갤러리 등이 있습니다.
무엇이 접근성 있는 캐러셀을만드나요?
- 캐러셀 이동이 너무 빠르거나 산만하여 텍스트를 읽기 어려울 수 있으므로 사용자가 캐러셀 이동을 일시 중지할 수 있어야 합니다.
- 캐러셀 항목 간 이동을 포함한 모든 기능은 키보드로 작동할 수 있어야 합니다.
- 캐러셀 항목에 대한 변경 사항은 스크린 리더 사용자를 포함한 모든 사용자에게 전달되어야 합니다.
- 키보드 위치('포커스')는 합리적이고 이해하기 쉬운 방식으로 관리되어야 합니다.
참고
캐러셀은 콘텐츠를 찾기 어려울 수 있기 때문에 사용성 측면에서 이의를 제기할 수 있습니다. 접근성을 보장하면 사용성도 향상될 수 있습니다.
이것이 왜 중요한가요?
일반적으로 캐러셀은 눈에 잘 띄는 위치에 있으며 탐색 기능을 제공하거나 페이지 콘텐츠를 표시하는 데 사용됩니다. 접근성 있는 캐러셀은 다음과 같은 많은 웹사이트 사용자에게 필수적입니다.
- 키보드 탐색 및 음성 입력 소프트웨어를 사용하는 사용자는 개별 항목 사이를 탐색할 수 있습니다.
- 스크린 리더 사용자는 현재 표시되는 항목과 항목 사이를 탐색하는 방법을 이해할 수 있습니다.
- 움직임에 주의가 산만해지는 사용자는 애니메이션을 일시 중지할 수 있습니다.
- 읽는 데 시간이 더 필요한 사용자는 애니메이션을 일시 중지하여 캐러셀 콘텐츠를 읽고 이해할 수 있는 충분한 시간을 확보할 수 있습니다.
캐러셀 구조
구조적 마크업을 사용하면 캐러셀의 콘텐츠를 다양한 상황에서 사용할 수 있습니다. 예를 들어, 적절한 마크업이 적용된 캐러셀은 모바일 디바이스에서 기사 목록으로 표시될 수 있습니다.
일반 구조
콘텐츠 항목의 모음인 캐러셀은 일반적으로 <ul> 및 <li>를 사용하여 정렬되지 않은 목록으로 표시하는 것이 가장 좋습니다. 컨텍스트에 따라 다른 요소를 사용할 수도 있습니다.
모든 캐러셀은 사용자가 캐러셀을 쉽게 찾을 수 있도록 레이블이 지정된 영역으로 둘러싸야 합니다. 다음 예시에서는 <section> 요소를 사용하여 영역을 정의하고 aria-labelledby를 사용하여 레이블이 포함된 제목을 정의합니다.
페이지 영역 및 레이블에 대한 자세한 내용은 페이지 구조 자습서를 참조하세요.
<section class="carousel" aria-labelledby="carouselheading">
<h3 id="carouselheading" class="visuallyhidden">Recent news</h3>
<ul>
<li class="slide">…</li>
<li class="slide">…</li>
<li class="slide">…</li>
…
</ul>
</section>
이 코드에 대한 작업 데모 예제를 사용할 수 있습니다.
캐러셀 항목
캐러셀은 일련의 이미지를 표시하는 갤러리로 자주 사용됩니다. 그러나 티저, 기사 또는 웹 페이지의 전체 섹션과 같은 보다 복잡한 콘텐츠도 캐러셀 안에 표시할 수 있습니다. 모든 경우에 적절한 마크업을 사용하여 콘텐츠의 구조와 의미가 명확하게 전달되도록 하세요. 이러한 마크업에는 제목, 섹션, 목록, 기사 및 필요에 따라 기타 요소가 포함될 수 있습니다.
이 첫 번째 예는 이미지가 콘텐츠로 포함된 캐러셀 항목을 보여줍니다.
…
<li class="slide">
<img src="teddy1.jpg" alt="Space Teddy">
</li>
…
제목과 단락이 포함된 이 article의 예는 더 복잡한 콘텐츠를 어떻게 사용할 수 있는지 보여줍니다.
…
<li class="slide" style="background-image: url('teddy1.jpg');">
<article>
<h4>Space Teddy production reaches all-time high</h4>
<p>Teddies in Space Inc. has released outstanding numbers for the last solar year. The production of Space Teddies increased by 17%. The new version, scheduled to be released in a few months, will likely be the biggest Space Teddy release ever.</p>
…
</article>
</li>
…
기능
캐러셀 항목을 선택하고 캐러셀 항목의 변경 사항을 사용자에게 알리는 기능을 제공합니다.
이전 및 다음 버튼 추가
사용자가 항목 간에 전환할 수 있는 버튼을 제공하세요. <button> 요소를 사용하여 의미론적 의미, 보조 기술 지원 및 일관된 키보드 동작을 제공합니다. 버튼은 JavaScript를 사용할 수 있는 경우에만 작동하므로 JavaScript를 사용하여 버튼을 생성하고 추가합니다.
var ctrls = document.createElement('ul');
ctrls.className = 'controls';
ctrls.innerHTML = '<li>' +
'<button type="button" class="btn-prev">' +
'<img src="img/chevron-left.png" alt="Previous Item">' +
'</button>' +
'</li>' +
'<li>' +
'<button type="button" class="btn-next">' +
'<img src="img/chevron-right.png" alt="Next Item">' +
'</button>' +
'</li>';
ctrls.querySelector('.btn-prev').addEventListener('click', function(){
prevSlide(true);
});
ctrls.querySelector('.btn-next').addEventListener('click', function(){
nextSlide(true);
});
carousel.appendChild(ctrls);
이 코드에 대한 작업 데모 예제를 사용할 수 있습니다.
현재 항목 알리기
WAI-ARIA live region을 사용하여 스크린 리더 사용자에게 현재 어떤 항목이 표시되는지 알립니다. 이 예에서는 시각적으로 숨겨진 "polite" 라이브 영역이 사용되며 캐러셀이 로드될 때 캐러셀에 추가됩니다. 그런 다음 이전 또는 다음 버튼을 클릭하면 "항목 x의 y"(x는 현재 항목 번호, y는 항목 수)라는 텍스트가 이 live region으로 설정됩니다. 지원되는 스크린 리더는 이 텍스트를 알립니다.
사용자가 키보드 초점을 계속 제어할 수 있도록 합니다. 캐러셀이 자동으로 진행될 때 사용자가 페이지의 현재 위치에서 멀어지지 않도록 해야 합니다. 또한 이전 또는 다음 버튼을 사용할 때 키보드 초점을 이동하지 마십시오. 초점을 이동하면 사용자가 슬라이드를 앞뒤로 탐색하기가 더 어려워집니다.
WAI-ARIA에 대한 자세한 내용은 WAI-ARIA 개요, WAI-ARIA 저작 관행 및 사양에서 확인할 수 있습니다.
코드 : 캐러셀에 live region 추가
var liveregion = document.createElement('div');
liveregion.setAttribute('aria-live', 'polite');
liveregion.setAttribute('aria-atomic', 'true');
liveregion.setAttribute('class', 'liveregion visuallyhidden');
carousel.appendChild(liveregion);
코드 : live region의 텍스트를 변경하여 해당 텍스트가 알려지도록 함
if (announceItem) {
carousel.querySelector('.liveregion').textContent = 'Item ' + (new_current + 1) + ' of ' + slides.length;
}
네비게이션 버튼 추가
캐러셀의 각 항목에 대한 버튼을 표시하고 현재 항목을 강조 표시합니다. 이렇게 하면 사용자가 캐러셀 콘텐츠의 개요와 시퀀스 내 위치를 파악할 수 있으며 원하는 항목으로 바로 이동할 수 있습니다.
아래 예의 버튼이 있는 목록은 JavaScript를 사용하여 추가되었으며, 버튼에는 캐러셀 항목에 해당하는 번호가 있습니다. 버튼에는 해당 캐러셀 항목과 일치하는 번호가 지정되어 있습니다. 활성 캐러셀 항목의 버튼은 시각적으로 강조 표시되거나 시각적으로 숨겨진 텍스트(스크린 리더의 경우)를 사용하여 강조 표시됩니다.
활성 캐러셀 항목을 접근하기 쉬운 방식으로 강조 표시하는 방법에 대한 자세한 내용은 캐러셀 스타일링 항목을 참조하세요.
<ul class="slidenav">
<li>
<button class="current" data-slide="0">
<span class="visuallyhidden">News</span> 1
<span class="visuallyhidden">(Current Slide)</span>
</button>
</li>
<li>
<button data-slide="1">
<span class="visuallyhidden">News</span> 2
</button>
</li>
<li>
<button data-slide="2">
<span class="visuallyhidden">News</span> 3
</button>
</li>
</ul>
선택한 캐러셀 항목에 초점 맞추기
사용자가 이러한 탐색 버튼으로 항목을 선택하면 선택한 항목에 초점이 설정되어야 합니다. 이 경우 변경 또는 전환 후 현재 클래스가 설정된 <li> 요소에 초점을 설정해야 합니다. 이렇게 하면 키보드 및 보조 기술 사용자가 더 쉽게 상호 작용할 수 있습니다.
기본적으로 <li> 요소는 포커스를 받을 수 없습니다. tabindex 속성을 -1로 설정하면 자바스크립트를 통해 포커스를 받을 수 있도록 요소가 활성화됩니다.
애니메이션
사용자에게 캐러셀의 애니메이션을 제어할 수 있는 기능을 제공하세요. 애니메이션 일시 중지는 움직임이 산만하거나 읽는 데 더 많은 시간이 필요한 사람들에게 필수적입니다.
재생/중지 버튼 추가
사용자가 애니메이션을 중지하고 다시 시작할 수 있는 버튼을 제공하세요. 아래 예는 이러한 버튼을 마크업하는 방법을 보여줍니다. 애니메이션이 현재 실행 중인지 여부에 따라 버튼 레이블과 버튼의 기능이 변경됩니다.
코드 : 애니메이션이 실행될 때
<button data-action="stop"><span class="visuallyhidden">Stop Animation </span>■</button>
코드 : 애니메이션이 정지될 때
<button data-action="start"><span class="visuallyhidden">Start Animation </span>▶</button>
이 코드에 대한 작업 데모 예제를 사용할 수 있습니다.
참고
자바스크립트는 <button> 요소의 값과 해당 속성만 대체합니다. 버튼 전체를 바꾸면 키보드 포커스가 손실될 수 있습니다.
마우스 hover 및 키보드 포커스 시 일시 중지
마우스 포인터가 캐러셀 위에 있거나 키보드 포커스를 받으면 캐러셀 애니메이션을 일시 중지합니다. 마우스 커서 일시정지는 콘텐츠를 읽는 데 시간이 더 필요한 사용자에게 유용하며 캐러셀의 링크를 더 쉽게 클릭할 수 있습니다. 키보드 사용자는 캐러셀이 일시 중지되어도 위치를 잃지 않습니다.
carousel.addEventListener('mouseenter', suspendAnimation);
carousel.addEventListener('mouseleave', startAnimation);
carousel.addEventListener('focusin',
function(event) {
if (!hasClass(event.target, 'slide')) {
suspendAnimation();
}
}
);
carousel.addEventListener('focusout',
function(event) {
if (!hasClass(event.target, 'slide')) {
startAnimation();
}
}
);
참고
focusin 및 focusout 이벤트는 W3C 문서 객체 모델(DOM) 레벨 3 이벤트 사양(작업 초안)에 정의되어 있으며 많은 브라우저에서 구현되어 있습니다. 이 튜토리얼을 게시하는 시점에 Firefox에는 간단한 폴리필이 필요합니다.
보조 기술에서 전환되는 요소 숨기기
전환 중에는 현재 항목과 다음 항목이 표시됩니다. 이는 보조 기술에서 현재 항목이 사라진 상태에서 두 항목을 사용할 수 있음을 의미하므로 스크린 리더 사용자에게 혼란을 줄 수 있습니다.
다음 예제에서는 활성화 중인 항목에 in-transition 클래스를 가져와 표시합니다. 보조 기술에서 항목을 숨기려면 aria-hidden 속성을 true로 설정합니다. 전환이 완료되면 aria-hidden 속성이 제거됩니다.
slides[new_next].className = 'next slide'
+ ((transition == 'next') ? ' in-transition' : '');
slides[new_next].setAttribute('aria-hidden', 'true');
slides[new_prev].className = 'prev slide'
+ ((transition == 'prev') ? ' in-transition' : '');
slides[new_prev].setAttribute('aria-hidden', 'true');
slides[new_current].className = 'current slide';
slides[new_current].removeAttribute('aria-hidden');
스타일링
버튼 크기
적절한 크기의 버튼과 링크를 사용하고 주변에 공백을 두어 손재주가 약한 사람도 캐러셀을 더 쉽게 사용할 수 있도록 하세요. 이는 모바일 디바이스 등 터치스크린을 사용하는 사람들에게도 유용합니다. 텍스트 블록에 인라인이 아닌 버튼과 링크는 최소 44×44 CSS 픽셀이어야 합니다.
명도대비
텍스트, 링크 및 버튼의 전경과 배경의 명도대비가 충분한지 확인합니다. 텍스트나 버튼이 이미지 위에 배치된 경우 이는 어려울 수 있습니다. 이 경우 (반)불투명한 배경색을 사용하면 사용된 이미지에 관계없이 대비를 유지하는데 도움이 될 수 있습니다.
명도대비 요구 사항에 대한 자세한 내용은 전경과 배경 간에 충분한 명도대비 제공을 참조하세요.
버튼 상태 표시
캐러셀에 추가된 탐색 버튼은 일반적으로 크기가 작기 때문에 적절한 이름과 레이블 외에도 색상과 모양으로 버튼의 상태를 표시하는 것이 중요합니다. 이렇게 하면 사람들이 버튼과 현재 상태를 쉽게 구분할 수 있습니다.
다음 예에서는 현재 표시되지 않은 항목과 연결된 버튼에 채워진 사각형이 사용됩니다. 표시된 항목의 버튼은 모서리가 둥글고 색상이 반전되어 있습니다. 사용자가 마우스를 사용하여 이러한 버튼 위로 마우스를 가져가거나 키보드를 사용하여 초점을 맞추면 테두리가 점선으로 표시됩니다.
이 코드에 대한 작업 데모 예제를 사용할 수 있습니다.
전체 코드
/* Focusin/out event polyfill (for Firefox) by nuxodin
* Source: https://gist.github.com/nuxodin/9250e56a3ce6c0446efa
*/
!function(){
var w = window,
d = w.document;
if( w.onfocusin === undefined ){
d.addEventListener('focus' ,addPolyfill ,true);
d.addEventListener('blur' ,addPolyfill ,true);
d.addEventListener('focusin' ,removePolyfill ,true);
d.addEventListener('focusout' ,removePolyfill ,true);
}
function addPolyfill(e){
var type = e.type === 'focus' ? 'focusin' : 'focusout';
var event = new CustomEvent(type, { bubbles:true, cancelable:false });
event.c1Generated = true;
e.target.dispatchEvent( event );
}
function removePolyfill(e){
if(!e.c1Generated){ // focus after focusin, so chrome will the first time trigger two times focusin
d.removeEventListener('focus' ,addPolyfill ,true);
d.removeEventListener('blur' ,addPolyfill ,true);
d.removeEventListener('focusin' ,removePolyfill ,true);
d.removeEventListener('focusout' ,removePolyfill ,true);
}
setTimeout(function(){
d.removeEventListener('focusin' ,removePolyfill ,true);
d.removeEventListener('focusout' ,removePolyfill ,true);
});
}
}();
/*
Carousel Prototype
Eric Eggert for W3C
*/
var myCarousel = (function() {
"use strict";
// Initial variables
var carousel, slides, index, slidenav, settings, timer, setFocus, animationSuspended;
// Helper function: Iterates over an array of elements
function forEachElement(elements, fn) {
for (var i = 0; i < elements.length; i++)
fn(elements[i], i);
}
// Helper function: Remove Class
function removeClass(el, className) {
if (el.classList) {
el.classList.remove(className);
} else {
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
// Helper function: Test if element has a specific class
function hasClass(el, className) {
if (el.classList) {
return el.classList.contains(className);
} else {
return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
}
// Initialization for the carousel
// Argument: set = an object of settings
// Possible settings:
// id <string> ID of the carousel wrapper element (required).
// slidenav <bool> If true, a list of slides is shown.
// animate <bool> If true, the slides can be animated.
// startAnimated <bool> If true, the animation begins
// immediately.
// If false, the animation needs
// to be initiated by clicking
// the play button.
function init(set) {
// Make settings available to all functions
settings = set;
// Select the element and the individual slides
carousel = document.getElementById(settings.id);
slides = carousel.querySelectorAll('.slide');
carousel.className = 'active carousel';
// Create unordered list for controls, and attach click events to previous and next slide
var ctrls = document.createElement('ul');
ctrls.className = 'controls';
ctrls.innerHTML = '<li>' +
'<button type="button" class="btn-prev"><img src="chevron-left.png" alt="Previous Item"></button>' +
'</li>' +
'<li>' +
'<button type="button" class="btn-next"><img src="chevron-right.png" alt="Next Item"></button>' +
'</li>';
ctrls.querySelector('.btn-prev')
.addEventListener('click', function () {
prevSlide(true);
});
ctrls.querySelector('.btn-next')
.addEventListener('click', function () {
nextSlide(true);
});
carousel.appendChild(ctrls);
// If the carousel is animated or a slide navigation is requested in the settings, another unordered list that contains those elements is added. (Note that you cannot supress the navigation when it is animated.)
if (settings.slidenav || settings.animate) {
slidenav = document.createElement('ul');
slidenav.className = 'slidenav';
if (settings.animate) {
var li = document.createElement('li');
if (settings.startAnimated) {
li.innerHTML = '<button data-action="stop"><span class="visuallyhidden">Stop Animation </span>■</button>';
} else {
li.innerHTML = '<button data-action="start"><span class="visuallyhidden">Start Animation </span>▶</button>';
}
slidenav.appendChild(li);
}
if (settings.slidenav) {
forEachElement(slides, function(el, i){
var li = document.createElement('li');
var klass = (i===0) ? 'class="current" ' : '';
var kurrent = (i===0) ? ' <span class="visuallyhidden">(Current Item)</span>' : '';
li.innerHTML = '<button '+ klass +'data-slide="' + i + '"><span class="visuallyhidden">News</span> ' + (i+1) + kurrent + '</button>';
slidenav.appendChild(li);
});
}
slidenav.addEventListener('click', function(event) {
var button = event.target;
if (button.localName == 'button') {
if (button.getAttribute('data-slide')) {
stopAnimation();
setSlides(button.getAttribute('data-slide'), true);
} else if (button.getAttribute('data-action') == "stop") {
stopAnimation();
} else if (button.getAttribute('data-action') == "start") {
startAnimation();
}
}
}, true);
carousel.className = 'active carousel with-slidenav';
carousel.appendChild(slidenav);
}
// Add a live region to announce the slide number when using the previous/next buttons
var liveregion = document.createElement('div');
liveregion.setAttribute('aria-live', 'polite');
liveregion.setAttribute('aria-atomic', 'true');
liveregion.setAttribute('class', 'liveregion visuallyhidden');
carousel.appendChild(liveregion);
// After the slide transitioned, remove the in-transition class, if focus should be set, set the tabindex attribute to -1 and focus the slide.
slides[0].parentNode.addEventListener('transitionend', function (event) {
var slide = event.target;
removeClass(slide, 'in-transition');
if (hasClass(slide, 'current')) {
if(setFocus) {
slide.setAttribute('tabindex', '-1');
slide.focus();
setFocus = false;
}
}
});
// When the mouse enters the carousel, suspend the animation.
carousel.addEventListener('mouseenter', suspendAnimation);
// When the mouse leaves the carousel, and the animation is suspended, start the animation.
carousel.addEventListener('mouseleave', function(event) {
if (animationSuspended) {
startAnimation();
}
});
// When the focus enters the carousel, suspend the animation
carousel.addEventListener('focusin', function(event) {
if (!hasClass(event.target, 'slide')) {
suspendAnimation();
}
});
// When the focus leaves the carousel, and the animation is suspended, start the animation
carousel.addEventListener('focusout', function(event) {
if (!hasClass(event.target, 'slide') && animationSuspended) {
startAnimation();
}
});
// Set the index (=current slide) to 0 – the first slide
index = 0;
setSlides(index);
// If the carousel is animated, advance to the
// next slide after 5s
if (settings.startAnimated) {
timer = setTimeout(nextSlide, 5000);
}
}
// Function to set a slide the current slide
function setSlides(new_current, setFocusHere, transition, announceItemHere) {
// Focus, transition and announce Item are optional parameters.
// focus denotes if the focus should be set after the
// carousel advanced to slide number new_current.
// transition denotes if the transition is going into the
// next or previous direction.
// If announceItem is set to true, the live region’s text is changed (and announced)
// Here defaults are set:
setFocus = typeof setFocusHere !== 'undefined' ? setFocusHere : false;
transition = typeof transition !== 'undefined' ? transition : 'none';
announceItem = typeof announceItemHere !== 'undefined' ? announceItemHere : false;
new_current = parseFloat(new_current);
var length = slides.length;
var new_next = new_current+1;
var new_prev = new_current-1;
// If the next slide number is equal to the length,
// the next slide should be the first one of the slides.
// If the previous slide number is less than 0.
// the previous slide is the last of the slides.
if(new_next === length) {
new_next = 0;
} else if(new_prev < 0) {
new_prev = length-1;
}
// Reset slide classes
for (var i = slides.length - 1; i >= 0; i--) {
slides[i].className = "slide";
}
// Add classes to the previous, next and current slide
slides[new_next].className = 'next slide' + ((transition == 'next') ? ' in-transition' : '');
slides[new_next].setAttribute('aria-hidden', 'true');
slides[new_prev].className = 'prev slide' + ((transition == 'prev') ? ' in-transition' : '');
slides[new_prev].setAttribute('aria-hidden', 'true');
slides[new_current].className = 'current slide';
slides[new_current].removeAttribute('aria-hidden');
// Update the text in the live region which is then announced by screen readers.
if (announceItem) {
carousel.querySelector('.liveregion').textContent = 'Item ' + (new_current + 1) + ' of ' + slides.length;
}
// Update the buttons in the slider navigation to match the currently displayed item
if(settings.slidenav) {
var buttons = carousel.querySelectorAll('.slidenav button[data-slide]');
for (var j = buttons.length - 1; j >= 0; j--) {
buttons[j].className = '';
buttons[j].innerHTML = '<span class="visuallyhidden">News</span> ' + (j+1);
}
buttons[new_current].className = "current";
buttons[new_current].innerHTML = '<span class="visuallyhidden">News</span> ' + (new_current+1) + ' <span class="visuallyhidden">(Current Item)</span>';
}
// Set the global index to the new current value
index = new_current;
}
// Function to advance to the next slide
function nextSlide(announceItem) {
announceItem = typeof announceItem !== 'undefined' ? announceItem : false;
var length = slides.length,
new_current = index + 1;
if(new_current === length) {
new_current = 0;
}
// If we advance to the next slide, the previous needs to be
// visible to the user, so the third parameter is 'prev', not
// next.
setSlides(new_current, false, 'prev', announceItem);
// If the carousel is animated, advance to the next
// slide after 5s
if (settings.animate) {
timer = setTimeout(nextSlide, 5000);
}
}
// Function to advance to the previous slide
function prevSlide(announceItem) {
announceItem = typeof announceItem !== 'undefined' ? announceItem : false;
var length = slides.length,
new_current = index - 1;
// If we are already on the first slide, show the last slide instead.
if(new_current < 0) {
new_current = length-1;
}
// If we advance to the previous slide, the next needs to be
// visible to the user, so the third parameter is 'next', not
// prev.
setSlides(new_current, false, 'next', announceItem);
}
// Function to stop the animation
function stopAnimation() {
clearTimeout(timer);
settings.animate = false;
animationSuspended = false;
_this = carousel.querySelector('[data-action]');
_this.innerHTML = '<span class="visuallyhidden">Start Animation </span>▶';
_this.setAttribute('data-action', 'start');
}
// Function to start the animation
function startAnimation() {
settings.animate = true;
animationSuspended = false;
timer = setTimeout(nextSlide, 5000);
_this = carousel.querySelector('[data-action]');
_this.innerHTML = '<span class="visuallyhidden">Stop Animation </span>■';
_this.setAttribute('data-action', 'stop');
}
// Function to suspend the animation
function suspendAnimation() {
if(settings.animate) {
clearTimeout(timer);
settings.animate = false;
animationSuspended = true;
}
}
// Making some functions public
return {
init:init,
next:nextSlide,
prev:prevSlide,
goto:setSlides,
stop:stopAnimation,
start:startAnimation
};
});
var carousel = new myCarousel();
carousel.init({
id: 'carousel',
slidenav: true,
animate: true,
startAnimated: true
});
묶음 글 목록
[A11Y] - 웹접근성 튜토리얼 - 2. 페이지 구조
[A11Y] - 웹접근성 튜토리얼 - 3. 메뉴(네비게이션)
[A11Y] - 웹접근성 튜토리얼 - 7. 캐러셀
이 글은 W3C의 웹접근성 튜토리얼을 번역한 글입니다.
'A11Y' 카테고리의 다른 글
[번역] ARIA aria-label 속성 (0) | 2023.08.07 |
---|---|
[번역] 웹접근성 튜토리얼 - 6. 폼 (0) | 2023.07.06 |
[번역] 웹접근성 튜토리얼 - 5. 테이블(표) (0) | 2023.07.06 |
[번역] 웹접근성 튜토리얼 - 4. 이미지 (0) | 2023.07.06 |
[번역] 웹접근성 튜토리얼 - 3. 메뉴(네비게이션) (0) | 2023.07.06 |