Accessible Slider Module
Based on the W3C/WAI recommendations here: https://www.w3.org/WAI/tutorials/carousels/
by jorgeluis
HTML
<section class="carousel-container" aria-labelledby="carouselheading">
<h3 id="carouselheading" role="presentation" class="visuallyhidden">Featured news</h3>
<div id="carousel" class="carousel">
<ul>
<li class="slide">
<div class="slide-content">
<h4 class="slide-title">Accessible Slider Module</h4>
<p>Inspired by a <a href="https://www.w3.org/WAI/tutorials/carousels/">W3C/WAI post</a> about accessible carousels.</p>
<p><a href="https://www.w3.org/WAI/tutorials/carousels/">Read more</a></p>
</div>
</li>
<li class="slide" style="background-image: url(http://placehold.it/600x200/234);">
<div class="slide-content">
<h4 class="slide-title">Background image</h4>
<p>For background images, best to add them as inline style attribute (just background-image) to the .slide element.</p>
<p>See the html</p>
</div>
</li>
<li class="slide">
<div class="slide-content">
<h4 class="slide-title">This example shows the .slidenav at the bottom</h4>
<p>With play/pause control and numbered buttons</p>
<p>I also used <code>title</code> attributes on previous and next svg arrows.</p>
</div>
</li>
</ul>
</div>
</section>
SCSS
.visuallyhidden {
overflow : hidden;
position : absolute;
clip : rect(0 0 0 0);
height : 1px;
width : 1px;
margin : -1px;
padding : 0;
border : 0;
}
.active .slide {
display: table !important;
visibility: hidden;
transition: left .6s ease-out;
}
.active .slide.current {
visibility: visible;
left: 0;
}
.active .slide.next {
left: 100%;
}
.active .slide.prev {
left: -100%;
}
.active .slide.next.in-transition,
.active .slide.prev.in-transition {
visibility:visible;
}
.carousel, .slide {
padding:0;
margin: 0;
overflow: hidden;
}
.carousel {
position: relative;
}
.carousel ul {
margin:0;
padding: 0;
}
.slide {
display: table;
height: 360px;
background-position: center center;
background-size: cover;
position: relative;
margin-bottom:1em;
}
.slide-content {
display: table-cell;
padding: 60px;
vertical-align: middle;
}
.slide-title {
font-size: 3em;
margin: 0;
}
.carousel.active {
height: 360px;
position:relative;
background-color: #222;
color: #f3f3f3;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
a, a:visited {
color: tomato;
}
}
.active .slide {
border: none;
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 200;
}
.slide.current {
display:block;
z-index: 500;
}
.btn-prev,
.btn-next {
position:absolute;
z-index: 700;
transform: translateY(-50%);
top: 50%;
border: 0;
line-height: 1;
padding: 10px 5px;
background-color: transparent;
transition: padding .4s ease-out;
}
.btn-next:hover,
.btn-next:focus,
.btn-prev:hover,
.btn-prev:focus {
padding-left: 15px;
padding-right:15px;
}
.btn-prev {
left: 0;
}
.btn-next {
right: 0;
}
.btn-prev svg,
.btn-next svg {
width: 40px;
}
.btn-prev .nav-arrow,
.btn-next .nav-arrow {
fill: none;
stroke: rgba(255,255,255, 0.6);
stroke-width: 3;
stroke-linecap: round;
stroke-miterlimit: 10;
}
/* slidenav is the bottom labels...
JavaScript
/* focusin/out event polyfill (firefox) */
!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 tow 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);
});
}
}();
var myCarousel = (function() {
var carousel, slides, index, slidenav, settings, timer, setFocus, animationSuspended;
function forEachElement(elements, fn) {
for (var i = 0; i < elements.length; i++)
fn(elements[i], i);
}
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'), ' ');
}
}
function hasClass(el, className) {
if (el.classList) {
return el.classList.contains(className);
} else {
return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
}
function init(set) {
settings = set;
carousel = document.getElementById(settings.id);
slides = carousel.querySelectorAll('.slide');
carousel.className = 'active carousel';
var ctrls =...