Evita pulsaciones no deseadas al hacer scroll con "Pointer-events: none"

Cómo evitar pulsaciones no deseadas y los repaints y reflows innecesarios al hacer scroll

Evita pulsaciones no deseadas al hacer scroll con "Pointer-events: none"

Por Kseso ✎ 4

Uno de los problemas a los que se enfrentan los usuarios con dispositivos táctiles al desplazar hacer scroll son los clicks o pulsaciones accidentales con todo lo que ello pueda conllevar.

Pero no son sólo ellos quienes "sufren" el efecto de los eventos "accidentales" mientras se desplaza el contenido. Paul Lewis en html5rocks.com publicó un artículo, "Avoiding Unnecessary Paints" sobre lo que supone para el navegador (recursos y trabajo) los :hover accidentales mientras se hace scroll debido a los "repaints y reflows" que se ve obligado a realizar.

Evita pulsaciones no deseadas al hacer scroll con "Pointer-events: none"AVISO DE AUTORÍA Y CRÉDITOS:
la técnica que voy a compartir contigo es original de @ryanseddon, publicada en su página "THE CSS NINJA": 60fps scrolling using pointer-events: none.
Yo sólo me hago eco de ella para darla a conocer entre los lectores de mi blog. Por favor, visita el artículo original, que en la fuente se encuentra el mejor agua.

if scroll 'pointer-events: none'

La solucción propuesta por @ryanseddon la encuentro de lo más sencilla y elegante. Sólo es necesario deshabilitar los eventos sobre el body (y sus contenidos) en el momento de iniciarse el scroll y mientras dura el desplazamiento.

Ésto es tan fácil como declarar la regla css oportuna y aplicar la clase .disable-hover al 'body' mientras se hace scroll.

.disable-hover, .disable-hover * { pointer-events: none !important; }

El selector .disable-hover * y el valor '!important' es necesario por si a algún elemento se le hubiese declarado un valor de 'auto' para esta propiedad.

A partir de esa declaración Css sólo se necesita aplicar la clase al body cuando se la necesita. Para ello Css no ofrece solucción, por lo que hay que recurrir a js:

var body = document.body, timer; window.addEventListener('scroll', function() { clearTimeout(timer); if(!body.classList.contains('disable-hover')) { body.classList.add('disable-hover') } timer = setTimeout(function(){ body.classList.remove('disable-hover') },500); }, false);

Ahora ya puedes hacer scroll sin miedo a los clicks no deseados y evitar 'repaints y reflows' innecesarios mientras desplazas los contenidos.

Recuerda que la autoría y el mérito de esta realización son de @ryanseddon

Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Don Kseso Kseso

Comentarios: 4

  1. Muy buen tutorial, la pregunta ahora es... tenía entendido que el empleo del selector * estaba desaconsejado porque afectaba notable y negativamente al rendimiento del navegador, según se puede leer entre otros en las recomendaciones de Google para la optimización web. Por esa razón por ejemplo era mejor utilizar un reset css a los elementos que fuera necesario aplicarles margin:0 y padding:0 por ejemplo y no utilizar el * para todos (que esto sería mucho más rápido, fácil y reduciría las tipicas 5 líneas de css llenas de elementos conflictivos a menos de 1.). Porque ya estaba decidido a implementar esto hasta que vi el * y me he quedado dudando.

    ResponderEliminar
  2. Hola Pablo.
    Efectivamente, eso suelen decir del selector universal.
    Para demos y otros casos en los que apenas hay elementos en el html y poco Css yo suelo utilizar el mini reset con el ese selector.
    De todos formas, no se hasta cuánto será la sobrecarga y ralentización del navegador en equipos modernos y navegadores actuales. Nunca lo he visto cuantificado.

    En el caso del artículo si tanto te preocupa el uso de este selector siempre podrías actuar por otra vía: crear un elemento posicionado sobre todo el contenido (z-index). Es una idea a bote pronto y sin meditar.

    Un saludo

    ResponderEliminar
  3. Gracias por tu pronta respuesta, pues la veo una muy buena alternativa y en principio no lo encuentro problema alguno. Y parece mucho más precisa que la del selector *. Sólo faltaría probar si funciona, le echaré un ojo a ver...

    ResponderEliminar
    Respuestas
    1. Es verdad lo del consumo de recursos al usar un comodín. Lo comprobé hace mucho, cuando solamente funcionaba en IE, y tenía una máquina muy limitada. Pero también es cierto que hoy ese consumo no afecta la capacidad de los nuevos micros. De cualquier forma, siempre es mayor que los producidos por un repaint o un reflow, así que por ese lado casi que no conviene.

      Estaba pensando cómo interpretan los móviles de pantalla táctil el evento de arrastre para desplazar. Porque la acción tiene un inicio, un desarrollo y un fin. Es evidente que para el scroll se toma el inicio, pero se debe mantener para el 'desarrollo'; eso obliga a monitorear si el desplazamiento del usuario sigue, y así prolongar el movimiento de la página hasta que se detenga. Por supuesto, para eso deben tener una instrucción que verifique si el movimiento del dedo continúa ... cada corto tiempo. Algo como lo propuesto por Ryan Seddon para saber con javascript cuándo se termina el arrastre y quitar la clase agregada al 'body'.

      Lo de la cubierta es muy ingenioso, sólo habría que probar -justamente- donde empieza y termina la interpretación del evento de scroll. Porque una capa fija no se arrastra, y al ponerla sobre el documento el "envión" que damos en la pantalla y que precisa unos instantes de arrastre simplemente se va a perder. Entonces la capa debe acompañar a todo el documento, y ajustarse a sus medidas, porque el inicio del arrastre debe continuar sobre ella, hasta que la página se detenga y el escript del que hablamos cambie su display otra vez a none.

      Algo que me lleva justamente al motivo para escribir este comentario :
      ¿De veras podemos publicar javascript para modificar CSS?

      8D

      Eliminar

EsCss RSS del Blog RSSS Comentarios Humans.txt ᛯ Diseno por Kseso SiteMap