Cómo evitar los efectos de desplazamiento flotante para botones en dispositivos táctiles

144

He creado un carrusel con un botón anterior y otro siguiente que siempre están visibles. Estos botones tienen un estado de desplazamiento, se vuelven azules. En dispositivos táctiles, como iPad, el estado de desplazamiento es fijo, por lo que el botón permanece azul después de tocarlo. No quiero eso

  • Podría agregar una no-hoverclase ontouchendpara cada botón y hacer que mi CSS sea así: button:not(.no-hover):hover { background-color: blue; }pero eso probablemente sea bastante malo para el rendimiento, y no maneja dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse) correctamente.

  • Podría agregar una touchclase al documentElementy hacer mi CSS de esta manera: html:not(.touch) button:hover { background-color: blue; }Pero eso tampoco funciona bien en dispositivos con toque y mouse.

Lo que preferiría es eliminar el estado de desplazamiento ontouchend. Pero no parece que eso sea posible. Enfocar otro elemento no elimina el estado de desplazamiento. Tocar otro elemento manualmente, pero parece que no puedo activar eso en JavaScript.

Todas las soluciones que he encontrado parecen imperfectas. ¿Hay una solución perfecta?

Chris
fuente

Respuestas:

55

Puede eliminar el estado de desplazamiento al eliminar temporalmente el enlace del DOM. Ver http://testbug.handcraft.com/ipad.html


En el CSS tienes:

:hover {background:red;}

En el JS tienes:

function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}

Y luego en tu HTML tienes:

<a href="#" ontouchend="this.onclick=fix">test</a>
Darren Cook
fuente
3
@Chris Buen punto, cambié el ejemplo para configurar el controlador onclick en el evento ontouchend.
Sjoerd Visscher
44
Considere agregar un código demostrativo mínimo a su respuesta. ¡Gracias! stackoverflow.com/help/how-to-answer
2540625
1
@SjoerdVisscher Lo he pegado. A StackOverflow le gusta que el código esté en la respuesta, ya que los enlaces pueden desaparecer. (Y en este caso, se requiere no solo hacer clic, sino también ver la fuente y determinar qué bits son la técnica en cuestión).
Darren Cook,
2
@KevinBorders sí, en algunos dispositivos, el retraso de tiempo entre la eliminación y la reinserción del elemento puede ser muy notable. Desafortunadamente, encontré en mi dispositivo Android 4.4 que hacer esto sin setTimeout no funcionó.
Rodney
1
La idea es interesante, pero me pareció un poco desigual y no es ampliamente compatible con todos los dispositivos táctiles. Preferiría una solución menos invasiva basada en la detección de soporte táctil y CSS puro como esta stackoverflow.com/a/39787268/885464
Lorenzo Polidori
83

Una vez que se implemente CSS Media Queries Nivel 4 , podrá hacer esto:

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}

O en inglés: "Si el navegador admite el desplazamiento apropiado / verdadero / real / no emulado (por ejemplo, tiene un dispositivo de entrada principal similar a un mouse), aplique este estilo cuando buttonse desplace el mouse sobre".

Dado que esta parte del Nivel 4 de Consultas de medios hasta ahora solo se ha implementado en Chrome de última generación , escribí un polyfill para tratar esto. Utilizándolo, puede transformar el CSS futurista anterior en:

html.my-true-hover button:hover {
    background-color: blue;
}

(Una variación de la .no-touchtécnica) Y luego, usando JavaScript del lado del cliente del mismo polyfill que detecta el soporte para el desplazamiento, puede alternar la presencia de la my-true-hoverclase en consecuencia:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
cvrebert
fuente
¡Gracias! Para mis propósitos, esto parece ser compatible con la mayoría de los navegadores caniuse.com/#search=media%20consulta y funciona de manera brillante, ¡gracias!
ragamufin
3
En su lugar, debe mirar caniuse.com/#feat=css-media-interaction y verá que no es compatible con Firefox e IE11 :( así que necesita el polyfill
CherryDT
Parece que el polyfill ya no es compatible (el repositorio está archivado) y requiere jQuery ...
amoebe
Esto ahora es ampliamente compatible con los navegadores móviles y funciona de maravilla. Creo que debería ser la respuesta aceptada.
Trevor Burnham
Este es definitivamente el más fácil de implementar y la mejor respuesta. Funciona en Firefox en Android Mobile y PC. No estoy seguro acerca de los dispositivos de doble toque y mouse.
HalfMens
28

Este es un problema común sin una solución perfecta. El comportamiento de desplazamiento es útil con un mouse y en su mayoría perjudicial con el tacto. Para agravar el problema están los dispositivos que admiten el tacto y el mouse (¡simultáneamente, no menos!) Como Chromebook Pixel y Surface.

La solución más limpia que he encontrado es habilitar solo el comportamiento de desplazamiento si no se considera que el dispositivo admite entrada táctil.

var isTouch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

if( !isTouch ){
    // add class which defines hover behavior
}

Por supuesto, pierdes el control sobre dispositivos que pueden soportarlo. Sin embargo, a veces el cursor pasa más que el enlace en sí mismo, por ejemplo, tal vez desee mostrar un menú cuando se coloca un elemento. Este enfoque le permite probar la existencia del tacto y quizás adjuntar condicionalmente un evento diferente.

He probado esto en iPhone, iPad, Chromebook Pixel, Surface y una variedad de dispositivos Android. No puedo garantizar que funcionará cuando se agregue una entrada táctil USB genérica (como un lápiz) a la mezcla.

Tim Medora
fuente
1
Impresionante, esto funcionó para mí, a diferencia de la respuesta de wiki / Darren Cook de la comunidad.
Jannik
1
Buena respuesta. Esta es una solución similar: stackoverflow.com/a/39787268/885464
Lorenzo Polidori
11

Con Modernizr puedes apuntar tus hovers específicamente para dispositivos no táctiles:

(Nota: esto no se ejecuta en el sistema de fragmentos de StackOverflow, verifique el jsfiddle en su lugar)

/* this one is sticky */
#regular:hover, #regular:active {
  opacity: 0.5;
}

/* this one isn't */
html.no-touch #no-touch:hover, #no-touch:active {
  opacity: 0.5;
}

Tenga en cuenta que :activeno es necesario enfocarlo .no-touchporque funciona como se espera tanto en dispositivos móviles como en computadoras de escritorio.

rachel
fuente
Esta es la mejor respuesta IMO PERO el ejemplo es incorrecto. Muestra el mismo estado de desplazamiento para dispositivos táctiles y no táctiles. Solo debe aplicar el estado de desplazamiento si .no-touchestá presente en la htmletiqueta. De lo contrario, esta respuesta obtiene mi sello de aprobación.
morrisbret
2
El problema es que ahora que los dispositivos habilitados para mouse que tienen pantallas táctiles están por todas partes, ya no puede confiar en este método. Sin embargo, no puedo ver otra forma de hacerlo ... esto es un gran dilema
amigo
Supongo que una forma de hacerlo sería usar Modernizr y una biblioteca como mobile-detect.js para asegurarse de que sea un teléfono o una tableta.
Gavin
Eres el hombre salvador, muchas gracias, esto funcionó perfectamente para dispositivos móviles
Shivam
9

Puede anular el efecto de desplazamiento para dispositivos que no admiten el desplazamiento. Me gusta:

.my-thing {
    color: #BADA55;
}

.my-thing:hover {
    color: hotpink;
}

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}

Probado y verificado en iOS 12

Sugerencia para https://stackoverflow.com/a/50285058/178959 por señalar esto.

OrgánicaPanda
fuente
Esta es la solución más moderna, no requiere javascript ni manipulación DOM, tiene soporte completo para el navegador (excepto IE) y debería ser la respuesta aceptada.
funkju
8
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});
Verard Sloggett
fuente
Puede mejorar esta respuesta usando un on () en lugar de un clic (). Al eliminar el elemento del DOM y volver a adjuntarlo, perdí mis eventos de clic. Cuando reescribí mi función con el, enlazando al elemento, luego eliminando y agregando trabajado. Por ejemplo: `$ ('body'). On ('click', '# elementwithhover', function () {// clone, insertafter, remove}); Voy a votar esto si haces ese cambio.
Will Lanni
El verdadero clon conserva el evento de clic en el nuevo elemenet tomando el lugar del elemento con el cursor suspendido. el elemento original se elimina del dom después de su clonación.
Verard Sloggett
hermano impresionante, 10x
Kaloyan Stamatov
Horas de búsqueda de una solución y esto finalmente proporcionó una. ¡Un millón de gracias!
phil917
8

A partir de 4 formas de lidiar con el desplazamiento flotante en dispositivos móviles : Aquí hay una manera de agregar o quitar dinámicamente una " can touch" clase al documento en función del tipo de entrada actual del usuario. También funciona con dispositivos híbridos donde el usuario puede cambiar entre el tacto y un mouse / trackpad:

<script>

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")

    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }

    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }

    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

</script>
hojaldres de coco
fuente
Esta es la mejor manera que encuentro, además, si aumenta el temporizador a 1000 ms, también puede cubrir la presión prolongada, consulte aquí . ¡Buena cosa!
lowtechsun
3

Iba a publicar mi propia solución, pero comprobando si alguien ya la había publicado, encontré que @Rodney casi lo hizo. Sin embargo, lo perdió un último elemento crucial que lo hizo inflexible, al menos en mi caso. Quiero decir, yo también tomé la misma .fakeHoverclase de adición / eliminación vía mouseentery mouseleavedetección de eventos, pero eso solo, per se , actúa casi exactamente como "genuino" :hover. Quiero decir: cuando tocas un elemento en tu tabla, no detectará que lo has "dejado", manteniendo así el estado "falso".

Lo que hice fue simplemente escuchar click, también, así que cuando "toco" el botón, disparo manualmente a mouseleave.

Si este es mi código final:

.fakeHover {
    background-color: blue;
}


$(document).on('mouseenter', 'button.myButton',function(){
    $(this).addClass('fakeHover');
});

$(document).on('mouseleave', 'button.myButton',function(){
    $(this).removeClass('fakeHover');
});

$(document).on('button.myButton, 'click', function(){
    $(this).mouseleave();
});

De esta manera, mantienes tu hoverfuncionalidad habitual cuando usas un mouse cuando simplemente "pasas el mouse" sobre tus botones. Bueno, casi todo: el único inconveniente de alguna manera es que, después de hacer clic en el botón con el mouse, no estará en hoverestado. Al igual que si hicieras clic y rápidamente quitaras el puntero del botón. Pero en mi caso puedo vivir con eso.

Pere
fuente
2

Esto es lo que se me ocurrió hasta ahora después de estudiar el resto de las respuestas. Debería ser capaz de admitir usuarios táctiles, de mouse o híbridos.

Cree una clase de desplazamiento independiente para el efecto de desplazamiento. Por defecto, agregue esta clase de desplazamiento a nuestro botón.

No queremos detectar la presencia de soporte táctil y deshabilitar todos los efectos de desplazamiento desde el principio. Como mencionan otros, los dispositivos híbridos están ganando popularidad; las personas pueden tener soporte táctil pero quieren usar un mouse y viceversa. Por lo tanto, solo elimine la clase de desplazamiento cuando el usuario realmente toque el botón.

El siguiente problema es, ¿qué pasa si el usuario quiere volver a usar el mouse después de tocar el botón? Para resolver eso, necesitamos encontrar un momento oportuno para volver a agregar la clase de desplazamiento que hemos eliminado.

Sin embargo, no podemos volver a agregarlo inmediatamente después de eliminarlo, porque el estado de desplazamiento todavía está activo. Es posible que no queramos destruir y recrear todo el botón también.

Entonces, pensé en usar un algoritmo de espera ocupada (usando setInterval) para verificar el estado de desplazamiento. Una vez que el estado de desplazamiento está desactivado, podemos volver a agregar la clase de desplazamiento y detener la espera ocupada, volviendo al estado original donde el usuario puede usar el mouse o el tacto.

Sé que la espera ocupada no es tan buena, pero no estoy seguro si hay un evento apropiado. He considerado agregarlo nuevamente en el evento mouseleave, pero no fue muy robusto. Por ejemplo, cuando aparece una alerta después de tocar el botón, la posición del mouse cambia pero el evento mouseleave no se activa.

var button = document.getElementById('myButton');

button.ontouchstart = function(e) {
  console.log('ontouchstart');
  $('.button').removeClass('button-hover');
  startIntervalToResetHover();
};

button.onclick = function(e) {
  console.log('onclick');
}

var intervalId;

function startIntervalToResetHover() {
  // Clear the previous one, if any.
  if (intervalId) {
    clearInterval(intervalId);
  }
  
  intervalId = setInterval(function() {
    // Stop if the hover class already exists.
    if ($('.button').hasClass('button-hover')) {
      clearInterval(intervalId);
      intervalId = null;
      return;
    }
    
    // Checking of hover state from 
    // http://stackoverflow.com/a/8981521/2669960.
    var isHovered = !!$('.button').filter(function() {
      return $(this).is(":hover");
    }).length;
    
    if (isHovered) {
      console.log('Hover state is active');
    } else {
      console.log('Hover state is inactive');
      $('.button').addClass('button-hover');
      console.log('Added back the button-hover class');
      
      clearInterval(intervalId);
      intervalId = null;
    }
  }, 1000);
}
.button {
  color: green;
  border: none;
}

.button-hover:hover {
  background: yellow;
  border: none;
}

.button:active {
  border: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='myButton' class='button button-hover'>Hello</button>

Editar: Otro enfoque que probé es llamar e.preventDefault()dentro de ontouchstart o ontouchend. Parece detener el efecto de desplazamiento al tocar el botón, pero también detiene la animación de clic del botón y evita que se llame a la función de clic cuando se toca el botón, por lo que debe llamarlos manualmente en el controlador ontouchstart o ontouchend. No es una solución muy limpia.

Kevin Lee
fuente
1

Fue útil para mí: enlace

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
mineroot
fuente
Debe llamar a hoverTouchUnstick () una vez desde el controlador de eventos global ontouchstart. Y esta solución funcionaría perfectamente.
Jusid
1

Agregue este código JS a su página:

document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';

ahora en su CSS antes de cada desplazamiento, agregue la clase de desplazamiento así:

.hover .foo:hover {}

Si el dispositivo es táctil, la clase de cuerpo estará vacía, de lo contrario, su clase se desplazará y se aplicarán las reglas.

Ali
fuente
No funcionó para mí, pero esto sí:document.body.className = 'ontouchstart' in window ? '' : 'hover';
drskullster
1

Podría agregar una clase de no-hover ontouchend para cada botón, y hacer que mi CSS sea así> this: button: not (.no-hover): hover {background-color: blue; } pero eso probablemente sea bastante malo para el rendimiento, y no maneja> dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse)> correctamente.

Este es el punto de partida correcto. Siguiente paso: aplicar / eliminar la clase nohover en los siguientes eventos (demostración con jQuery)

buttonelement
 .on("touchend touchcancel",function(){$(this).addClass("nohover")})
 .on("touchstart mouseover",function({$(this).removeClass("nohover")});   

Aviso: si desea aplicar otras clases al elemento de tono, el: not (.nohover) en el CSS ya no funcionará como se esperaba. Luego, debe agregar una definición separada con el valor predeterminado y una etiqueta importante para sobrescribir el estilo de desplazamiento: .nohover {background-color: white! Important}

¡Esto incluso debería manejar dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse) correctamente! Y no creo que este sea un gran asesino de rendimiento ...

Sascha Hendel
fuente
1

Una solución que me ha funcionado:

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

Agregue este código a su hoja de estilo.

Quería deshacerme del fondo gris que aparece en iOS Safari cuando se hace clic en un enlace. Pero parece hacer más. ¡Ahora hacer clic en un botón (con una :hoverpseudoclase!) Se abre de inmediato! Solo lo probé en un iPad, no sé si funcionará en otros dispositivos.

Leon Vogler
fuente
1

Creo que he encontrado una solución elegante (mínimo js) para un problema similar:

Usando jQuery, puede activar el desplazamiento sobre el cuerpo (o cualquier otro elemento), usando .mouseover()

Así que simplemente adjunto este controlador al ontouchendevento del elemento de esta manera:

var unhover = function() {
  $("body").mousover();  
};
.hoverable {
  width: 100px;
  height: 100px;
  background: teal;
  cursor: pointer;
}

.hoverable:hover {
  background: pink;
}
<div class="hoverable" ontouchend={unhover}></div>

Esto, sin embargo, solo elimina: suspender la pseudoclase del elemento después de que se haya activado algún otro evento táctil, como deslizar u otro toque

Ian Averno
fuente
1
Para su fragmento de código, el cuadrado aún permanece rosado después de tocarlo. ¿Supongo que realmente no resolvió el problema planteado en esta pregunta?
Kevin Lee
Esta solución no funciona. Primero, usó el método incorrecto para invocar un evento, debe usar .trigger () . En segundo lugar, no funciona en safari móvil de ninguna manera.
xHocquet
1

Tengo una buena solución que me gustaría compartir. Primero debe detectar si el usuario está en un dispositivo móvil como este:

var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());

Luego solo agrega:

if (!touchDevice) {
    $(".navbar-ul").addClass("hoverable");
}

Y en CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}
Michał Reszka
fuente
2
No funciona en dispositivos híbridos, por ejemplo, PC con pantalla táctil de Windows.
cspolton
1

Pasé por un problema similar, mi aplicación era compatible para todos los tamaños de pantalla, tenía muchos efectos de desplazamiento en el tamaño de la pantalla del escritorio dispositivos basados ​​en el / mouse, y más tarde me di cuenta de que los dispositivos táctiles estaban causando una condición conocida como pegajosa -hover y fue un obstáculo para que la aplicación funcione correctamente para los usuarios de dispositivos táctiles.

Estábamos haciendo uso de SCSS en nuestra aplicación. y definí un mixin para cuidar el dispositivo táctil.

@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}

y luego coloqué todas mis clases de css bajo el fragmento mencionado a continuación.

   @include hover-support() {
    // Your css-classes or css that you want to apply on those devices that support hover.
   }

Por ejemplo, teníamos una clase para animar un ícono, y que solía activarse una vez que pasamos el cursor sobre el ícono como se puede ver desde css, pero en un dispositivo táctil se vio afectado por el efecto de desplazamiento y luego lo coloqué dentro de @ incluir hover-support () para garantizar que el hover solo se aplique a aquellos dispositivos que lo soporten.

@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}
Divyanshu Rawat
fuente
1

Aquí hay un código JavaScript simple que no requiere que el desarrollador edite CSS o escriba nuevas reglas CSS. Escribí esto para los botones Bootstrap con class="btn", pero funcionará con cualquier botón que tenga un nombre de clase específico.

Los pasos son:

  1. determinar si este es un dispositivo táctil
  2. si es así, repita cada regla CSS en document.styleSheets
  3. eliminar cualquier regla que contenga ambos .btny:hover

La eliminación de todas las .btn :hoverreglas CSS garantiza que no habrá un efecto de desplazamiento visual en un botón.

Paso 1: Detectar dispositivo táctil

Verifique la consulta de medios para detectar la presencia de (hover: none):

    const hasMatchMedia = typeof window.matchMedia !== 'undefined';
    /**
     * determine if device is touch-capable
     * true - device is touch-capable
     * false - device is not touch-capable
     * null - unable to determine touch capability
     * @return {null|boolean}
     */
    const hasTouch = () => {
      if (hasMatchMedia) {
        return window.matchMedia('(hover: none)').matches;
      }
      return null;
    };

Paso 2: Eliminar las reglas CSS que contienen `btn` y`: hover`

    /**
     * remove all CSS rules contaning both '.btn' and ':hover'
     * @return {number} count of rules deleted
     */
    function removeBtnHovers () {

      let rulesDeleted = 0;

      // recursively delete '.btn:hover' rules
      function recursiveDelete (rules, styleSheet) {

        if (typeof rules === 'undefined' ||
          typeof rules.length === 'undefined' ||
          rules.length <= 0) {
          return;
        }

        // iterate in reverse order,
        // deleting any rule containing both '.btn' and ':hover'
        const ruleLen = rules.length;
        for (let i = ruleLen - 1; i >= 0; i--) {
          const rule = rules[i];
          if (typeof rule.cssRules === 'undefined') {
            // a standard rule, evaluate it
            const cssText = rule.cssText;
            if (typeof cssText === 'string' &&
              cssText.includes('.btn') &&
              cssText.includes(':hover')) {
              styleSheet.deleteRule(i);
              rulesDeleted++;
            }
          } else {
            // rule contains cssRules, iterate over them
            recursiveDelete(rule.cssRules, rule);
          }
        }
      }

      // iterate over all style sheets in document
      for (const styleSheet of document.styleSheets) {
        let rules = styleSheet.cssRules;
        if (!rules) { continue; }
        recursiveDelete(rules, styleSheet);
      }
      return rulesDeleted;
    }

El código completo está en GitHub y npm .

Demostración en vivo en terrymorse.com .

Terrymorse
fuente
¿No elimina esto también el efecto de desplazamiento para dispositivos con pantalla táctil con mouse / trackpad?
Jensei
@Jensei Posiblemente. Las reglas de desplazamiento se eliminan si el dispositivo coincide @media (hover:none)o cuando el usuario toca la pantalla por primera vez. Puede probarlo en la página de demostración en vivo para estar seguro.
Terrymorse
0

Puede establecer el color de fondo en el :activeestado y proporcionar :focus el fondo predeterminado.

si establece el color de fondo a través de onfocus/ontouch, el estilo de color permanece una vez que el :focusestado ha desaparecido.
También necesita reiniciar onblurpara restaurar el valor predeterminado bg cuando se pierde el foco.

G-Cyrillus
fuente
Pero me gustaría mantener el efecto de desplazamiento para los usuarios del mouse.
Chris
: hover y: active pueden recibir el mismo CSS, está en: foco, tienes el problema. En realidad, si configura el color de fondo a través del enfoque, el estilo de color permanece una vez que el enfoque se ha ido. necesita un reinicio en onlur también para restaurar el valor predeterminado bg
G-Cyrillus
0

Esto funcionó para mí: poner el estilo de desplazamiento en una nueva clase

.fakehover {background: red}

Luego agregue / elimine la clase cuando sea necesario

$(".someclass > li").on("mouseenter", function(e) {
  $(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
  $(this).removeClass("fakehover");
});

Repita para eventos de inicio táctil y toque. O cualquier evento que desee para obtener el resultado deseado, por ejemplo, quería que el efecto de desplazamiento se activara en una pantalla táctil.

Rodney
fuente
0

Basado en la respuesta de Darren Cooks, que también funciona si mueve el dedo sobre otro elemento.

Consulte Buscar dedo del elemento encendido durante un evento de toque

jQuery(function() {
    FastClick.attach(document.body);
});
// Prevent sticky hover effects for buttons on touch devices
// From https://stackoverflow.com/a/17234319
//
//
// Usage:
// <a href="..." touch-focus-fix>..</a>
//
// Refactored from a directive for better performance and compability
jQuery(document.documentElement).on('touchend', function(event) {
  'use strict';

  function fix(sourceElement) {
    var el = $(sourceElement).closest('[touch-focus-fix]')[0];
    if (!el) {
      return;
    }
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    par.insertBefore(el, next);
  }

  fix(event.target);
  var changedTouch = event.originalEvent.changedTouches[0];
  // http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchend-event
  if (!changedTouch) {
    return;
  }
  var touchTarget = document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
  if (touchTarget && touchTarget !== event.target) {
    fix(touchTarget);
  }
});

Codepen Demo

jantimon
fuente
0

Puedes intentarlo de esta manera.

javascript:

var isEventSupported = function (eventName, elementName) {
    var el = elementName ? document.createElement(elementName) : window;
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported && el.setAttribute) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
    }
    el = null;
    return isSupported;
};

if (!isEventSupported('touchstart')) {
    $('a').addClass('with-hover');
}

css:

a.with-hover:hover {
  color: #fafafa;
}
Lorenzo Polidori
fuente
0

Lo que hice hasta ahora en mis proyectos fue revertir los :hovercambios en los dispositivos táctiles:

.myhoveredclass {
    background-color:green;
}
.myhoveredclass:hover {
    background-color:red;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
    .myhoveredclass:hover, .myhoveredclass:active, .myhoveredclass:focus {
        background-color:green;
    }
}

Todos los nombres de clase y colores con nombre solo para fines de demostración ;-)

z00l
fuente
0

Esto funciona perfectamente en 2 pasos.

  1. Configure su etiqueta corporal para que sea así <body ontouchstart="">. No soy fanático de este "hack", pero permite que Safari en iOS reaccione a los toques al instante. No estoy seguro de cómo, pero funciona.

  2. Configure su clase táctil de esta manera:

    // I did this in SASS, but this should work with normal CSS as well
    
    // Touchable class
    .example {
    
        // Default styles
        background: green;
    
        // Default hover styles 
        // (Think of this as Desktop and larger)
        &:hover {
            background: yellow;
        }
    
        // Default active styles
        &:active {
            background: red;
        }
    
        // Setup breakpoint for smaller device widths
        @media only screen and (max-width: 1048px) {
    
            // Important!
            // Reset touchable hover styles
            // You may want to use the same exact styles as the Default styles
            &:hover {
                background: green;
            }
    
            // Important!
            // Touchable active styles
            &:active {
                background: red;
            }
        }
    }

Es posible que también desee eliminar cualquier animación en su clase táctil. Android Chrome parece ser un poco más lento que iOS.

Esto también dará como resultado que se aplique el estado activo si el usuario se desplaza por la página mientras toca su clase.

Miguel
fuente
0

Algunos de los :hover :focus :activeproblemas pegajosos o atascados en los dispositivos móviles pueden ser causados ​​por la falta, <meta name="viewport" content="width=device-width">ya que los navegadores intentan manipular la pantalla.

GEkk
fuente
0

La solución para mí fue después de tocar el dedo, clonar y reemplazar el nodo ... odio hacer esto, pero incluso tratar de volver a pintar el elemento con offsetHeight no funcionaba

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );
Prohibición
fuente
Al final, esto no funcionó para mí ... mi caso tendría que clonar un ES6 completo que se extiende y varios oyentes de eventos y simplemente comenzó a ser complicado resolver una cosa tan pequeña.
Prohibición del
0

Se puede lograr intercambiando una clase HTML. Debería ser menos propenso a fallas técnicas que eliminar todo el elemento, especialmente con enlaces de imágenes grandes, etc.

También podemos decidir si queremos flotar estados de desplazamiento al desplazarse con el tacto (touchmove) o incluso agregar un tiempo de espera para retrasarlos.

El único cambio significativo en nuestro código será usar clases HTML adicionales, como <a class='hover'></a>elementos que implementan el nuevo comportamiento.

HTML

<a class='my-link hover' href='#'>
    Test
</a>

CSS

.my-link:active, // :active can be turned off to disable hover state on 'touchmove'
.my-link.hover:hover {

    border: 2px dotted grey;
}

JS (con jQuery)

$('.hover').bind('touchstart', function () {

   var $el;
   $el = $(this);
   $el.removeClass('hover'); 

   $el.hover(null, function () {
      $el.addClass('hover');
   });
});

Ejemplo

https://codepen.io/mattrcouk/pen/VweajZv

-

Sin embargo, no tengo ningún dispositivo con mouse y táctil para probarlo correctamente.

Maciek Rek
fuente
0

Desde 2020 Puede agregar estilos de desplazamiento dentro de la consulta de medios

@media (hover: hover) and (pointer: fine) {
    /* css hover class/style */
}

Esta consulta de medios indica que los estilos funcionarán en navegadores que no emulan: desplace el mouse para que NO funcione en navegadores táctiles.

Dawid Świtoń
fuente