jsor / jcarousel

Riding carousels with jQuery.
https://sorgalla.com/jcarousel/
MIT License
2k stars 734 forks source link

Accessibility using the keyboard #149

Closed Dupond closed 13 years ago

Dupond commented 13 years ago

Hello,

On my blog (here : http://sxjpl.free.fr/biblio/), I have a carousel in order to view several posts.

For accessibility reasons, when you browse using the keyboard, it would be nice if the jcarousel could stop if the "prev" or "next" button has the focus (so that you can read the entire post BEFORE it automatically scrolls to the next one). It should stop too if the title of one of the posts inside of the carousel has the focus.

I have tried to add this to my jscript, but with no success : carousel.clip.focus(function() { carousel.stopAuto(); }, function() { carousel.startAuto(); });

Any idea ? Thanx in advance ! Best regards, Dupond

jsor commented 13 years ago

From the jQuery docs:

This event is implicitly applicable to a limited set of elements, such as form elements (<input>, <select>, etc.) and links (<a href>).

Maybe that helps.

Dupond commented 13 years ago

Thank you very much for your answer.

So I thought this code would work : jQuery('#carousel-editos .post-title').focus(function() { carousel.stopAuto(); }, function() { carousel.startAuto(); });

but it doesn't... Since .post-title is the classe of a link, shouldn't it work ? Or do I have misunderstood what you meant ? Sorry for my poor english, I'm not sure if I have understood well...

jsor commented 13 years ago

No, you have something like:

<h4 class="post-title handwriting"><a href="">...</a></h4>

So, .post-title is on the <h4> element. You should do something like:

jQuery('#carousel-editos .post-title a')
Dupond commented 13 years ago

Pfff... I'm really sorry that you have lost your time with this. Thanx a lot. It works like a charm now : if the title of a post (inside of the carousel) has the focus, then the carousel will stop. But :

  1. When the focus is lost, the carousel should restart... unfortunately, it doesn't. I thought the "carousel.startAuto()" function should do this ?
  2. When the title of the first post (inside of the carousel) has the focus, it stops ; then if I hit the Tab key again, the second article inside of the carousel is displayed ; then the third one, etc... Well, this is perfect... except that the width of the article is not good anymore, so the post is badly displayed (some parts of it are hidden). Is this just a CSS problem of my fault... or is jCarousel invovled ?
  3. Last one : is there a way to go to the prev or next post using the arrow keys, and the mouse scroll wheel ?

Thank you very much for your help !

jsor commented 13 years ago
  1. focus() does not accept a second paremeter like hover(). You should use blur() which is the counterpart of focus():

    jQuery('#carousel-editos .post-title')
    .focus(function() { carousel.stopAuto(); })
    .blur(function() { carousel.startAuto(); });
  2. In this case its the behaviour of the browser which causes the item to jump in the visible area. You could try something like this (not tested):

    jQuery('#carousel-editos .post-title')
    .focus(function(e) { 
       carousel.stopAuto();
       carousel.scroll(parseInt(this.parents('.jcarousel-item').attr('jcarouselindex')));
       e.preventDefault();
    });
  3. Not out-of-the-box. But you can combine jCarousel with jquery-mouswheel or jquery.hotkeys.
Dupond commented 13 years ago

Thank you for the first point. It works better now indeed :) But the second one doesn't : the behaviour is just like before (that is to say : the posts are not displayed well at all). I have the following code :

function mycarousel_initCallback(carousel) { carousel.buttonNext.bind('click', function() { carousel.startAuto(0); }); carousel.buttonPrev.bind('click', function() { carousel.startAuto(0); }); carousel.clip.hover(function() { carousel.stopAuto(); }, function() { carousel.startAuto(); }); jQuery('#carousel-editos .post-title a') .focus(function(e) { carousel.stopAuto(); carousel.scroll(parseInt(this.parents('.jcarousel-item').attr('jcarouselindex'))); e.preventDefault(); }) .blur(function() { carousel.startAuto(); }); };

Furthermore, when a user uses the keyboard to navigate, hitting the "tab" key does give the focus to the title of one of the posts (inside of the carousel), but this is not necessarily the one that is displayed on the screen. In fact, the focus always goes to the first post of the carousel. So sometimes you don't know where your focus is :(

jsor commented 13 years ago

My code was just a shot in the dark. Its an interesting topic. If you focus an element which is hidden by overflow: hidden, the brower automatically moves the element into the visible area. The drawback is, that the css value for left is still 0 although in "reality" its not. I have no solution right now, sorry. Have to investigate that further...

Dupond commented 13 years ago

Thank you for your explanations.

Since it seems difficult, there's maybe another easier solution : I've installed jquery.hotkeys ; then I should be able to say "now if the "tab" key is used, then we go to the next post". But once more, it doesn't work. I had tried this : jQuery('#carousel-editos .post-title a') .focus(function() { carousel.stopAuto(); $.hotkeys.add('left', function(){carousel.prev();}); $.hotkeys.add('right', function(){carousel.next();}); $.hotkeys.add('tab', function(){carousel.next();}); }) .blur(function() { carousel.startAuto(); });

jsor commented 13 years ago

Yep, because you bind it in focus(). Thats too late because the element already has focus then...

Dupond commented 13 years ago

I understand that. Thanx. But the key thing is : if you have several carousels on the same page, or if someone uses the tab or arrow keys for something else, then the "left"/"right"/"tab" keys should only have an effect if the title of a post (inside of the carousel) has the focus...

Anyway, even the following code doesn't work : jQuery(document).ready(function() { jQuery('#carousel-editos').jcarousel({ scroll: 1, animation: 'slow', auto: 6, wrap: 'last', buttonPrevHTML: '<', buttonNextHTML: '>', itemVisibleInCallback: {onBeforeAnimation: carousel_derniersbillets_itemVisibleInCallback}, initCallback: mycarousel_initCallback }); $.hotkeys.add('left', function(){carousel.prev();}); $.hotkeys.add('right', function(){carousel.next();}); $.hotkeys.add('tab', function(){carousel.next();}); });

Dupond commented 13 years ago

OK the following code seems to work : jQuery('#carousel-editos .post-title a') .focus(function() { carousel.stopAuto(); }) .blur(function() { carousel.startAuto(); }) .bind('keyup', 'left', function (evt) { carousel.prev(); return false; }) .bind('keyup', 'right', function (evt) { carousel.next(); return false; }) .bind('keyup', 'tab', function (evt) { carousel.next(); return false; }); But there is still the following problem : if the focus is given OR the "tab" key is pressed, the carousel should display the first post inside of it (since the first post has the focus, even if it is not displayed). So is there a carousel.Display('first') or carousel.JumpTo('first') or something like that ? Thank you for your help.

jsor commented 13 years ago

Its carousel.scroll(1).

Dupond commented 13 years ago

OK, thank you, I think it's nearly done : the following code really improves the accessibility for people like me who can only browse using the keyboard : jQuery('#carousel-editos .post-title a') .bind('keyup', 'left', function () { carousel.prev(); return false; }) .bind('keyup', 'right', function () { carousel.next(); return false; }) .bind('keyup', 'tab', function () { carousel.next(); return false; }) .focus(function() { carousel.scroll(1); carousel.stopAuto(); }) .blur(function() { carousel.startAuto(); }); Nevertheless, there are two problems left :

  1. Strangely, since I've installed jquery.hotkeys, the carousel doesn't stop anymore even if a title has the focus ;
  2. I thought the 'tab' code would cancel the default behavior of the browser (which you explained to me in your posts before)... but unfortunately it doesn't :( Any idea about those two ones ? If you don't, anyway, as I said it's really better than before :) So it doesn't really matter... So anyway, thank you very much for all the help you have provided to me. Carousels and accessibility with the keyboard still seem to be a little bit of a challenge :) Best regards, Dupond
Dupond commented 13 years ago

OK, if I use "keydown" instead of "keyup", the "tab" key displays the next post correctly... but then I can't go out of the carousel anymore using the keyboard :) I would need a : "if I hit the "tab" key AND the displayed post inside of the carousel is the last one, then go out of the carousel"...

Dupond commented 13 years ago

I have finally succeeded (stopAuto() didn't work because I had not the last version of jCarousel. Now it's OK).

Here is the code that I've used : carousel.buttonNext.bind('click', function() { carousel.startAuto(0); }); carousel.buttonPrev.bind('click', function() { carousel.startAuto(0); }); carousel.clip.hover(function() { carousel.stopAuto(); }, function() { carousel.startAuto(); }); jQuery('#carousel-editos .post-title a') .bind('keyup', 'left', function () { carousel.prev(); return false; }) .bind('keyup', 'right', function () { carousel.next(); return false; }) .bind('keydown', 'tab', function () { jQuery('#carousel-lastevents a').focus(); carousel.startAuto(); return false; }) .focus(function() { carousel.scroll(1); carousel.stopAuto(); }) It's not perfect, since using the "tab" key doesn't display all the posts inside of the carousel (but as you explained it to me, this seems to be a bigger problem due to the actual browsers), but as I said it's much better than before. Thank you for all the time you have given to me, and have a good week everyone ! Now I consider that this ticket is closed... ... unless, in the future, you find a solution to the "browser and tab key" problem :)