Слайдеры и кнопка Tab

Все js-слайдеры подвержены одному смешному багу: они ломаются при использовании кнопки Tab. Если на каком-то слайде есть ссылка, слайдер обязательно сломается при переходе на нее табом. Несколько примеров на слайдере, который не ломается (oh, the irony):

Сломанный слайдер на apple.com
Сломанный слайдер Swipe
Сломанный слайдер Стима

Дело в том, что при фокусировании ссылки, скрытой за overflow: hidden, браузер заботлибо промотает вам содержимое блока, чтобы ссылка оказалась в поле зрения. Да, у блоков с overflow: hidden тоже есть scrollLeft, и он работает так же, как и в случае с overflow: auto.

Решение: ловим событие focus внутри слайдов. Когда событие случается, переключаем слайд на тот, в котором произошло событие, и сбрасываем scrollLeft контейнера слайдов. Событие focus не бабблится, поэтому используем капчуринг, чтобы поймать его на уровне слайдов (почитать про бабблинг и капчуринг). Для старых IE используем фоллбек в виде события focusin, которое бабблится.

Выполняем для каждого слайда:

// Сначала фоллбек для старых IE
slide.onfocusin = function() {
// Сбрасываем скролл
_this.scrollLeft = 0;
// И еще раз с нулевым таймаутом, потому что в вебките скролл
// выставляется позже события. Первый ресет оставляем, чтобы
// в других браузерах не дергалось.
setTimeout(function() {
_this.scrollLeft = 0;
}, 0);

// Переключаем на слайд, к которому привязано событие
changeActiveSlide(i);
};

// Используем привязанную к `onfocusin` функцию уже
// в нормальном `addEventListener`
if (slide.addEventListener) {
// `true` включает капчуринг
slide.addEventListener('focus', slide.onfocusin, true);
}

Можно было бы обойтись событием focusin, но Firefox до сих пор не поддерживает его >:(

«Точки» под слайдером тоже должны дружить с клавиатурой. Чтобы не городить огород, достаточно просто сделать их доступными для табуляции (для этого выставляем им аттрибут tabindex="0") и включать нужный слайд по нажатию энтера.

Естественно, при этом нельзя отключать outline вокруг выделенной точки. Чтобы обводка вокруг точки работала при навигации с клавиатуры, но не мешалась при использовании мыши, существует два приема. Первый — убрать outline для псевдокласса :active, чтобы обводки не было во время нажатой кнопки мыши:

.peppermint.active > ul.dots > li:active {
outline: none;
}

Второй — снимать фокус после клика мышью:

addEvent(dot, 'click', (function(x, d) {
return function() {
d.blur(); //снимаем фокус с точки
changeActiveSlide(x); //переключаем слайд

...

};
})(i, dot), false);

Выше используется простая универсальная функция addEvent:

function addEvent(el, event, func, bool) {
el.addEventListener ?
el.addEventListener(event, func, !!bool) :
el.attachEvent('on'+event, func);
}

Хреновый способ убрать аутлайн, не стоит сбрасывать позицию фокуса. Лучше воспользуйтесь этим методом.

Теперь слайдер адекватно работает с клавиатурой и исполняет (вроде бы) необходимый минимум «Руководства по обеспечению доступности веб-контента». Такие дела.