Desplazamiento suave y accesibilidad | Programar Plus

El desplazamiento suave (el cambio animado de posición dentro de la ventana gráfica desde el enlace de origen al ancla de destino) puede ser un detalle de interacción agradable agregado a un sitio, dando una sensación pulida a la experiencia. Si no me cree, mire cuántas personas han respondido al fragmento de desplazamiento suave aquí en CSS-Tricks.

desplazamiento suave vs salto abruptoDesplazamiento suave frente a saltos abruptos

Independientemente de cómo implemente la función, hay algunos problemas de accesibilidad que deben abordarse: administración de enfoque y animación.

Gestión del enfoque

Es importante asegurarse de que todo el contenido se puede acceder con el teclado solo porque algunos usuarios 100% confía en el teclado para navegar. Por lo tanto, cuando un usuario de teclado navega por el contenido y golpea un enlace que utiliza un desplazamiento suave, debería poder usarlo para navegar hasta el elemento de ancla de destino.

En otras palabras, cuando sigues un enlace, el foco del teclado también debería seguirlo y poder acceder al siguiente elemento después del objetivo. A continuación, se muestra un ejemplo de enlaces a anclajes de página en los que se mantiene el foco porque no se utiliza JavaScript:

Ejemplo donde se mantiene el enfoqueEl comportamiento predeterminado del navegador con enlaces a los anclajes de página y el enfoque se mantiene correctamente.

Pruébelo usted mismo: use la tecla de tabulación para navegar usando esta demostración. Tenga en cuenta que Safari / WebKit tiene un error destacado con respecto al enfoque del teclado.

Ejemplo de jQuery original

Veamos el ejemplo de jQuery de la publicación original:

$(function() {
  $('a[href*="https://css-tricks.com/smooth-scrolling-accessibility/#"]:not([href="https://css-tricks.com/smooth-scrolling-accessibility/#"])').click(function() {
    if (location.pathname.replace(/^//,'') == this.pathname.replace(/^//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=" + this.hash.slice(1) +"]');
      if (target.length) {
        $('html, body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });
});

Esto se implementa en una página del W3C:

Desplazamiento suave en el sitio web del W3Cel Skip Nav debe :focus en el contenido, pero esto no cambia el enfoque

Aquí, vemos que el enlace “Saltar al contenido” no se centra en el contenido al que se navegó. Entonces, si usamos este ejemplo, empeoramos la navegación para las personas que usan el teclado porque el usuario espera navegar hacia el contenido al que se dirige, pero no es así, porque el enfoque no se actualiza para reflejar el cambio.

Pruébelo usted mismo usando la tecla de tabulación para navegar con esta demostración.

¿Qué salió mal?

¿Por qué no funciona esto? Estamos usando JavaScript para controlar el comportamiento normal de vinculación del navegador (tenga en cuenta que la URL nunca se actualiza con el objetivo / #), lo que significa que debemos establecer el enfoque con JavaScript. En jQuery eso sería $(target).focus();.

Para que esto funcione en elementos de destino no enfocables (section, div, span, h1-6, ect), tenemos que configurar tabindex="-1" sobre ellos para poder $(target).focus();. Podemos agregar el tabindex="-1" directamente en elementos de destino no enfocables en el marcado html o agréguelo usando JavaScript como se ve aquí.

$(function() {
  $('a[href*="https://css-tricks.com/smooth-scrolling-accessibility/#"]:not([href="https://css-tricks.com/smooth-scrolling-accessibility/#"])').click(function() {
    if (location.pathname.replace(/^//,'') == this.pathname.replace(/^//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=" + this.hash.slice(1) +"]');
      if (target.length) {
        $('html, body').animate({
          scrollTop: target.offset().top
        }, 1000);
        target.focus(); // Setting focus
        if (target.is(":focus")){ // Checking if the target was focused
          return false;
        } else {
          target.attr('tabindex','-1'); // Adding tabindex for elements not focusable
          target.focus(); // Setting focus
        };
        return false;
      }
    }
  });
});

Pruébelo usted mismo usando la tecla de tabulación para navegar con esta demostración. ¡No olvides tu estilo: focus!

Centrar la funcionalidad en el desplazamiento en el sitio del W3C

¿Una mejor manera?

Podría ser mejor para los usuarios en general si manejamos esta función sin secuestrar el comportamiento normal de navegación del navegador. Por ejemplo, si sigue un enlace, puede volver con el botón Atrás del navegador. Además, puede marcar (o copiar y pegar) la URL actual y el navegador irá a ese destino específico desde el último enlace en el que hizo clic.

// URL updates and the element focus is maintained
// originally found via in Update 3 on http://www.learningjquery.com/2007/10/improved-animated-scrolling-script-for-same-page-links

// filter handling for a /dir/ OR /indexordefault.page
function filterPath(string) {
  return string
    .replace(/^//, '')
    .replace(/(index|default).[a-zA-Z]{3,4}$/, '')
    .replace(//$/, '');
}

var locationPath = filterPath(location.pathname);
$('a[href*="https://css-tricks.com/smooth-scrolling-accessibility/#"]').each(function () {
  var thisPath = filterPath(this.pathname) || locationPath;
  var hash = this.hash;
  if ($("https://css-tricks.com/smooth-scrolling-accessibility/#" + hash.replace(/#/, '')).length) {
    if (locationPath == thisPath && (location.hostname == this.hostname || !this.hostname) && this.hash.replace(/#/, '')) {
      var $target = $(hash), target = this.hash;
      if (target) {
        $(this).click(function (event) {
          event.preventDefault();
          $('html, body').animate({scrollTop: $target.offset().top}, 1000, function () {
            location.hash = target; 
            $target.focus();
            if ($target.is(":focus")){ //checking if the target was focused
              return false;
            }else{
              $target.attr('tabindex','-1'); //Adding tabindex for elements not focusable
              $target.focus(); //Setting focus
            };
          });       
        });
      }
    }
  }
});

Concéntrese en trabajar en el sitio del W3CEjemplo que muestra las actualizaciones de URL con cada ancla en la que se hace clic

Aquí, la URL se actualiza con cada ancla en la que se hace clic. Pruébelo usted mismo usando la tecla de tabulación para navegar usando esta demostración.

Ejemplo nativo

Veamos el ejemplo del navegador nativo de la publicación CSS-Tricks. (También hay un polyfill).

document.querySelector('#target-of-thing-clicked-on').scrollIntoView({ 
  behavior: 'smooth' 
});

Desafortunadamente, con este método, nos encontramos con el mismo problema que el método jQuery donde la página se desplaza dentro de la ventana gráfica, pero no actualiza el enfoque del teclado. Entonces, si queremos ir por esta ruta, aún tendríamos que configurar .focus() y asegurar que los elementos objetivo no enfocables reciban tabindex="-1".

Otra consideración aquí es la falta de una función de devolución de llamada para cuando el desplazamiento se detiene. Eso puede ser un problema o no. Movería el enfoque simultáneamente con el desplazamiento en lugar de al final, lo que puede o no ser un poco extraño. De todos modos, ¡habrá trabajo por hacer!

Movimiento y accesibilidad

Algunas personas pueden literalmente enfermarse por el movimiento rápido en la pantalla. Recomendaría una velocidad de movimiento lenta porque si el usuario va a saltar a través de una gran cantidad de contenido, puede causar un efecto vertiginoso si es demasiado rápido.

Además, no es mala idea ofrecer a los usuarios una forma de desactivar las animaciones. Afortunadamente, Safari 10.1 introdujo la consulta de medios de movimiento reducido que proporciona a los desarrolladores un método para incluir animación de una manera que se puede desactivar en el nivel del navegador.

/* JavaScript MediaQueryList Interface */
var motionQuery = window.matchMedia('(prefers-reduced-motion)');
if (motionQuery.matches) {
  /* reduce motion */
}
motionQuery.addListener( handleReduceMotionChanged );

Desafortunadamente, ningún otro navegador ha implementado esta función todavía. Entonces, hasta que el soporte se extienda más allá de un navegador, podemos brindarle al usuario una opción a través de la interfaz para habilitar / deshabilitar la animación que podría causar problemas a los usuarios.

<label>
  <input type="checkbox" id="animation" name="animation" checked="checked">
  Enable Animation
</label> 
$(this).click(function(event) {
  if ($('#animation').prop('checked')) {
    event.preventDefault();
    $('html, body').animate({scrollTop: $target.offset().top}, 1000, function() {
      location.hash = target;
      $target.focus();
      if ($target.is(":focus")) {
        return !1;
      } else {
        $target.attr('tabindex', '-1');
        $target.focus()
      }
    })
  }
});

Pruébelo usted mismo con esta demostración.

(Visited 1 times, 1 visits today)