Animation, accessibilité et CSS

Animation, accessibilité et CSS (le 4 décembre 2015)

Sur le dernier site sur lequel je travaille, mon graphiste m’a gentiment demandé d’animer mon plugin hide-show system, pour que les contenus apparaissent progressivement avec un bel effet de fondu. En cogitant un peu avec ma gentille stagiaire, nous sommes arrivés à une solution que je vous détaille ici.

PLugin Hide/Show

Les seuls moyens de rendre un contenu non focusable (au clavier) sont :

  1. soit de le cacher avec un display: none ;
  2. soit avec un visibility: hidden ;
  3. ou soit de rendre non focusables tous les éléments (dudit contenu) pouvant l’être via un tabindex="-1".

Mon plug-in avait utilisé la solution la plus simple, la première : display: none. Mes burger-icons utilisent la troisième, vu que les éléments cachés sont de type liens (et donc plus ou moins connus et prévisibles).

Quelques points à savoir :

  • Comme je l’avais écrit dans mon billet , on ne peut pas animer la propriété height de 0 à auto, il faut une valeur numérique. Dura lex sed lex.
  • Il faudra donc animer la propriété max-height de 0 à une valeur suffisante mais pas trop afin que l’animation soit rapide…
  • … et seul problème, un élément avec un max-height même à une valeur de 0 laisse son contenu focusable.
  • La propriété display n’est pas animable ou « transitionnable ». Dura lex sed lex².

Comme je n’ai aucune prévisibilité sur le contenu – il peut y avoir déjà des éléments avec tabindex="-1", cela devient très casse-pied, il faut les marquer pour les retrouver, etc. – j’ai écarté d’emblée la troisième solution. Comme la propriété display n’est pas animable, exit aussi. Il me reste donc la propriété visibility en roue de secours.

Rappelons son fonctionnement : cette propriété rend visible ou non le contenu auquel elle s’applique, mais elle ne change pas la place qu’il occupe, qu’il soit visible ou non.

J’ai bien essayé quelques animations CSS, mais hormis des résultats rigolos qui vous feraient vous inquiéter sur ma santé mentale, rien de bien tangible. Bref, l’idée est de revenir aux bases, les transitions CSS (après tout, on parle bien d’une transition entre deux états).

Bref, mon plug-in hide-show permet de connaitre l’état caché ou non caché une fois que le JavaScript applique lesdits états. Donc en supposant que j’ai utilisé l’attribut data-hideshow-prefix-class="animated" qui va donc préfixer les classes appliquées par ledit plug-in, cela nous donne .animated-expandmore__to_expand pour le contenu dans l’état « affiché » et [aria-hidden=true].animated-expandmore__to_expand pour le contenu dans l’état « caché ».

Pour être même plus précis : .animated-expandmore__to_expand cible tous les états et [aria-hidden=true].animated-expandmore__to_expand cible uniquement l’état caché (qui peut donc surcharger le précédent).

La première idée fut de faire cela (je mets le code sans préfixes pour des raisons de longueur) :

/* ouvert */
.animated-expandmore__to_expand {
display: block;
overflow: hidden;
max-height: 80em;
visibility: visible;
transition: visibility 1s ease, max-height 1s ease;
}
/* fermé */
[aria-hidden=true].animated-expandmore__to_expand {
display: block;
max-height: 0;
visibility: hidden;
}

Cela semble logique, toutefois, cela ne donne pas le résultat attendu : la propriété visibility n’a pas d’état « intermédiaire », c’est visible ou invisible. Si je ne la mets pas dans la transition, quand on cache le contenu, tout devient invisible d’un coup et se ferme ensuite. Pas génial.

Du coup, la propriété opacity va rentrer dans le jeu :

/* ouvert */
.animated-expandmore__to_expand {
display: block;
overflow: hidden;
opacity: 1;
max-height: 80em;
visibility: visible;
transition: visibility 1s ease, max-height 1s ease, opacity 1s ease;
}
/* fermé */
[aria-hidden=true].animated-expandmore__to_expand {
display: block;
opacity: 0;
max-height: 0;
visibility: hidden;
}

Là cela marche bien. Il y a toutefois un truc qui me chagrine, c’est l’état « indéfini » de la propriété visibility durant la transition. Cette propriété ne me sert in fine qu’à cacher le contenu au clavier. Du coup, cela me fait deux cas :

  • Quand on affiche le contenu, il faut que je passe de suite visibility de hidden à visible ;
  • Et quand on cache le contenu, il faut que visibility passe de visible à hidden uniquement à la fin de l’animation.

Bien sûr, hors de question – même si c’est faisable, je l’ai fait sur mon carrousel – de commencer à placer un listener pour récupérer en JavaScript la fin de l’animation CSS, c’est bien trop compliqué.

Je mets en gras les différences :

/* ouvert */
.animated-expandmore__to_expand {
display: block;
overflow: hidden;
opacity: 1;
max-height: 80em;
visibility: visible;
transition: visibility 0s ease, max-height 1s ease, opacity 1s ease;
transition-delay: 0s;
}
/* fermé */
[aria-hidden=true].animated-expandmore__to_expand {
display: block;
opacity: 0;
max-height: 0;
visibility: hidden;
transition-delay: 1s, 0s, 0s;
}

En fait, l’animation sur visibility se fera de suite… mais je place un délai sur la transition sur cette propriété dans un sens. Voilà comment il faut le comprendre :

  • Quand on va de fermé à ouvert, visibility passe instantanément à visible sans délai (on verra le contenu quand il va s’étendre) ;
  • Et quand on va d’ouvert à fermé, visibility passera de visible à hidden après l’animation, donc au bout d’une seconde.

Là, l’effet fonctionne bien, vous pouvez le voir sur la page de mon plugin hide-show system, je viens d’ajouter une rubrique Bonus: some animations?.

Voilà pour cette petite étude. N’hésitez pas à compléter/confirmer/infirmer, je suis preneur de retours avisés.

Permalien :

Flux RSS des commentaires de ce billet : https://www.nicolas-hoffmann.net/rss/commentaires.php?id_news=1680


Aucun commentaire pour le moment.

Ajouter un commentaire









L'option « Se souvenir de mes informations » utilise un cookie, elle ne sera pas effective si vous les avez désactivés.

Les balises HTML ne seront pas interprétées, il est donc inutile d'en mettre. Par contre, les sauts de lignes de votre commentaire seront pris en compte, ne mettez donc pas de <br />, le site s'en chargera. Bien sûr, un commentaire vide ne sera pas ajouté !

L'auteur (autrement dit moi) n'est pas responsable des éventuelles fautes d'orthographe dans les commentaires.
Tout propos raciste et/ou insultant sera supprimé sans préavis. Les commentaires hors de propos destinés à faire de la pub pour des sites seront également supprimés sans ménagement.

Je vous prie de me pardonner, j'ai énormément de mal à lire le "langage" SMS, il n'est donc pas du tout interdit de s'abstenir de l'utiliser. Qui plus est, vous avez sûrement un clavier digne de ce nom et pas celui d'un téléphone portable. Ne vous gênez pas pour utiliser l'option "Prévisualiser" si vous voulez vous relire avant de poster, je vous en remercie d'avance !

Cet article a été écrit par Nicolas Hoffmann.

Ce site est la propriété de Nicolas Hoffmann.
Tous droits réservés, les textes du blog sont publiés sous licence CC BY-NC-SA.