Como evitar efeitos de foco instantâneo de botões em dispositivos de toque

144

Eu criei um carrossel com um botão anterior e um próximo que estão sempre visíveis. Esses botões têm um estado de foco, eles ficam azuis. Em dispositivos sensíveis ao toque, como o iPad, o estado de foco é fixo, portanto o botão permanece azul depois de tocá-lo. Eu não quero isso

  • Eu poderia adicionar uma no-hoverclasse ontouchendpara cada botão e criar meu CSS dessa maneira: button:not(.no-hover):hover { background-color: blue; }mas isso provavelmente é muito ruim para o desempenho e não lida com dispositivos como o Chromebook Pixel (que possui tela sensível ao toque e mouse) corretamente.

  • Eu poderia adicionar uma touchclasse ao documentElemente fazer meu CSS assim: html:not(.touch) button:hover { background-color: blue; }Mas isso também não funciona direito em dispositivos com toque e mouse.

O que eu preferiria é remover o estado de foco ontouchend. Mas não parece que isso seja possível. Focar outro elemento não remove o estado de foco. Tocar em outro elemento manualmente, mas não consigo acioná-lo em JavaScript.

Todas as soluções que encontrei parecem imperfeitas. Existe uma solução perfeita?

Chris
fonte

Respostas:

55

Você pode remover o estado de foco ao remover temporariamente o link do DOM. Consulte http://testbug.handcraft.com/ipad.html


No CSS você tem:

:hover {background:red;}

No JS você tem:

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

E então no seu HTML você tem:

<a href="#" ontouchend="this.onclick=fix">test</a>
Darren Cook
fonte
3
@ Chris Good point, mudei o exemplo para definir o manipulador onclick no evento ontouchend.
Sjoerd Visscher
4
Por favor, considere adicionar um código demonstrativo mínimo à sua resposta. Obrigado! stackoverflow.com/help/how-to-answer
2540625 16/16
1
@SjoerdVisscher Eu colei. StackOverflow gosta que o código esteja na resposta, pois os links podem desaparecer. (E, neste caso, necessário não apenas através do clique, mas, em seguida, visualizar a fonte, e trabalhar fora quais bits são a técnica em questão.)
Darren Cozinhe
2
@KevinBorders yes em alguns dispositivos, o atraso entre a remoção e a reinserção do elemento pode ser muito perceptível. Infelizmente, eu encontrei no meu dispositivo Android 4.4 que fazer isso sem setTimeout não funcionou.
Rodney
1
A ideia é interessante, mas achei um pouco irregular e não é amplamente suportada em todos os dispositivos touch. Eu preferiria uma solução menos invasiva com base na detecção de apoio toque e css puro como este stackoverflow.com/a/39787268/885464
Lorenzo Polidori
83

Depois que o nível 4 das consultas de mídia CSS for implementado, você poderá fazer o seguinte:

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

Ou em inglês: "Se o navegador suportar pairar adequado / verdadeiro / real / não emulado (por exemplo, possui um dispositivo de entrada principal do tipo mouse), aplique esse estilo quando buttons passar o mouse sobre".

Como essa parte do nível 4 de consultas de mídia até agora só foi implementada no Chrome de ponta, escrevi um polyfill para lidar com isso. Com ele, você pode transformar o CSS futurista acima em:

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

(Uma variação na .no-touchtécnica) E, em seguida, usando algum JavaScript do cliente do mesmo polyfill que detecta suporte para pairar, é possível alternar a presença da my-true-hoverclasse de acordo:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
cvrebert
fonte
Obrigado! Para meus propósitos, isso parece ser suportado na maioria dos navegadores caniuse.com/#search=media%20queries e funciona de maneira brilhante, obrigado!
Ragamufin 17/08/19
3
Você precisa olhar para caniuse.com/#feat=css-media-interaction vez e você verá que não é suportado no Firefox e no IE11 :( então você precisa do polyfill
CherryDT
Parece que o polyfill não é mais suportado (repo é arquivada) e que exige jQuery ...
amoebe
Agora isso é amplamente suportado em navegadores móveis e funciona como um encanto. Eu acho que deve ser a resposta aceita.
Trevor Burnham
Esse é definitivamente o mais fácil de implementar e a melhor resposta. Funciona no Firefox no Android Mobile e PC. Não tenho certeza sobre dispositivos de toque duplo e mouse.
HalfMen 31/03
28

Este é um problema comum, sem solução perfeita. O comportamento de passar o mouse é útil com o mouse e, principalmente, prejudicial ao toque. Para agravar o problema, existem dispositivos compatíveis com toque e mouse (simultaneamente, nada menos!), Como o Chromebook Pixel e o Surface.

A solução mais limpa que encontrei é ativar o comportamento de pairar apenas se o dispositivo não suportar a entrada por toque.

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

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

Concedido, você perde o foco em dispositivos que podem suportá-lo. No entanto, algumas vezes o hover afeta mais que o próprio link, por exemplo, talvez você queira mostrar um menu quando um elemento é direcionado. Essa abordagem permite testar a existência do toque e, talvez, anexar condicionalmente um evento diferente.

Eu testei isso no iPhone, iPad, Chromebook Pixel, Surface e em uma variedade de dispositivos Android. Não posso garantir que funcione quando uma entrada de toque USB genérica (como uma caneta) for adicionada à mistura.

Tim Medora
fonte
1
Incrível, isso funcionou para mim, ao contrário do wiki da comunidade / resposta de Darren Cook.
Jannik
1
Boa resposta. Esta é uma solução semelhante: stackoverflow.com/a/39787268/885464
Lorenzo Polidori
11

Com o Modernizr, você pode direcionar seus hover especificamente para dispositivos sem toque:

(Nota: isso não é executado no sistema de trechos do StackOverflow, verifique o jsfiddle )

/* 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;
}

Observe que :activenão precisa ser segmentado .no-touchporque funciona conforme o esperado em dispositivos móveis e computadores.

Rachel
fonte
Esta é a melhor resposta IMO, mas o exemplo está incorreto. Está mostrando o mesmo estado de foco para dispositivos de toque e sem toque. Só deve aplicar o estado de foco se .no-touchestiver presente na htmltag. Caso contrário, esta resposta recebe meu selo de aprovação.
194 Morrisbret
2
O problema é que agora que os dispositivos habilitados para mouse que possuem telas sensíveis ao toque estão em todo lugar, você não pode mais confiar nesse método. No entanto não consigo ver muito de uma outra maneira de fazê-lo ... este é um dilema bastante
dudewad
Suponho que uma maneira de fazer isso seria usar o Modernizr e uma biblioteca como mobile-detect.js para garantir que seja um telefone ou um tablet.
Gavin
Você é o salvador, graças a isso funcionou perfeitamente para dispositivos móveis
Shivam
9

Você pode substituir o efeito de focalização para dispositivos que não suportam a focalização. Gostar:

.my-thing {
    color: #BADA55;
}

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

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

Testado e verificado no iOS 12

Dica para https://stackoverflow.com/a/50285058/178959 para apontar isso.

OrganicPanda
fonte
Essa é a solução mais moderna, sem necessidade de manipulação de javascript ou DOM, tem suporte total ao navegador (exceto o IE) e deve ser a resposta aceita.
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
fonte
Você pode melhorar esta resposta usando um on () em vez de um clique (). Ao remover o elemento do DOM e anexá-lo novamente, perdi meus eventos de clique. Quando reescrevi minha função com o on, vinculando ao elemento, removendo e adicionando trabalhado. Por exemplo: `$ ('body'). On ('click', '# elementwithhover', function () {// clone, insertafter, remove}); Vou votar se você fizer essa alteração.
que você precisa
o clone true preserva o evento click na nova elemenet, substituindo o elemento com o cursor suspenso. o elemento original está sendo removido do dom após sua clonagem.
Verard Sloggett
# 10
Kaloyan Stamatov #
Horas de busca por uma correção e isso finalmente forneceu uma. Graças um milhão!
phil917
8

De quatro maneiras de lidar com o foco instantâneo no celular : Aqui está uma maneira de adicionar ou remover dinamicamente uma can touchclasse " " do documento com base no tipo de entrada atual do usuário. Também funciona com dispositivos híbridos, nos quais o usuário pode alternar entre o toque e um 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>
sopros de coco
fonte
Esta é a melhor maneira que eu acho, além disso, se você aumentar o temporizador para 1000ms, também poderá cobrir a pressão longa, veja aqui . Coisas boas!
lowtechsun
3

Eu ia postar minha própria solução, mas, verificando se alguém já a postou, descobri que o @Rodney quase o fez. No entanto, ele perdeu uma última decisão crucial que a tornou sem sentido, pelo menos no meu caso. Quero dizer, eu também fiz a mesma .fakeHoveradição / remoção de classe via mouseentere mouseleavedetecção de eventos, mas só isso, por si só , funciona quase exatamente como "genuíno" :hover. Quero dizer: quando você toca em um elemento da sua tabela, ele não detecta que você o "deixou" - mantendo assim o estado "fakehover".

O que eu fiz foi simplesmente ouvir clicktambém, então, quando "toco" o botão, eu aciono manualmente a mouseleave.

Si este é o meu 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();
});

Dessa forma, você mantém sua hoverfuncionalidade usual ao usar o mouse, simplesmente "pairando" nos botões. Bem, quase tudo: a única desvantagem é que, depois de clicar no botão com o mouse, ele não estará em hoverestado. É como se você clicasse e rapidamente retirasse o ponteiro do botão. Mas no meu caso eu posso viver com isso.

Pere
fonte
2

Isso é o que eu venho até agora depois de estudar o restante das respostas. Ele deve ser capaz de oferecer suporte a usuários híbridos, apenas com toque, somente mouse.

Crie uma classe de foco separado para o efeito de foco. Por padrão, adicione essa classe de foco ao nosso botão.

Não queremos detectar a presença de suporte por toque e desativar todos os efeitos de foco instantâneo desde o início. Como mencionado por outros, os dispositivos híbridos estão ganhando popularidade; as pessoas podem ter suporte ao toque, mas desejam usar o mouse e vice-versa. Portanto, remova a classe de foco apenas quando o usuário realmente tocar no botão.

O próximo problema é: e se o usuário quiser voltar a usar o mouse depois de tocar no botão? Para resolver isso, precisamos encontrar um momento oportuno para adicionar de volta a classe hover que removemos.

No entanto, não podemos adicioná-lo de volta imediatamente após removê-lo, porque o estado de foco ainda está ativo. Podemos não querer destruir e recriar o botão inteiro também.

Então, pensei em usar um algoritmo de espera ocupada (usando setInterval) para verificar o estado de foco. Depois que o estado de foco é desativado, podemos adicionar novamente a classe de foco e interromper a espera ocupada, retornando ao estado original em que o usuário pode usar o mouse ou o toque.

Sei que esperar muito ocupado não é tão bom, mas não tenho certeza se há um evento apropriado. Eu considerei adicioná-lo novamente no evento mouseleave, mas não foi muito robusto. Por exemplo, quando um alerta é exibido depois que o botão é tocado, a posição do mouse muda, mas o evento do mouse não é acionado.

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>

Edit: Outra abordagem que tentei é chamar e.preventDefault()no ontouchstart ou ontouchend. Parece interromper o efeito de foco quando o botão é tocado, mas também interrompe a animação do clique no botão e evita que a função onclick seja chamada quando o botão é tocado, para que você precise chamá-los manualmente no manipulador ontouchstart ou ontouchend. Não é uma solução muito limpa.

Kevin Lee
fonte
1

Foi útil para mim: link

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
fonte
Você precisa chamar hoverTouchUnstick () uma vez no manipulador de eventos ontouchstart global. E essa solução funcionaria perfeitamente.
Jusid
1

Adicione este código JS à sua página:

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

agora em seu CSS antes de cada foco, adicione a classe foco assim:

.hover .foo:hover {}

Se o dispositivo for sensível ao toque, a classe do corpo estará vazia; caso contrário, sua classe ficará suspensa e as regras serão aplicadas!

Todos
fonte
Não funcionou para mim, mas isso fez:document.body.className = 'ontouchstart' in window ? '' : 'hover';
drskullster
1

Eu poderia adicionar uma classe no-hover ontouchend para cada botão e criar meu CSS como este: button: not (.no-hover): hover {background-color: blue; } mas isso provavelmente é muito ruim para o desempenho e não lida com dispositivos como o Chromebook Pixel (que possui tela sensível ao toque e mouse)> corretamente.

Este é o ponto de partida certo. Próxima etapa: aplicar / remover a classe nohover nos seguintes eventos (demo com jQuery)

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

Aviso: Se você deseja aplicar outras classes ao elemento button, o: not (.nohover) no CSS não funcionará mais conforme o esperado. Em vez disso, é necessário adicionar uma definição separada com valor padrão e uma tag! Important para substituir o estilo de foco: .nohover {background-color: white! Important}

Isso deve até manipular dispositivos como o Chromebook Pixel (que possui tela sensível ao toque e mouse) corretamente! E eu não acho que esse seja um grande assassino de desempenho ...

Sascha Hendel
fonte
1

Uma solução que funcionou para mim:

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

Adicione esse código à sua folha de estilo.

Eu queria me livrar do fundo cinza que aparece no iOS Safari quando um link é clicado. Mas parece fazer mais. Agora, clicando em um botão (com um :hoverpseudoclasse!) É aberto imediatamente! Só testei em um iPad, não sei se funcionará em outros dispositivos.

Leon Vogler
fonte
1

Acho que encontrei uma solução elegante (js mínima) para um problema semelhante:

Usando o jQuery, você pode ativar o foco no corpo (ou qualquer outro elemento), usando .mouseover()

Então, simplesmente anexo um manipulador this ao ontouchendevento do elemento da seguinte maneira:

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

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

No entanto, isso remove apenas: pseudoclasse suspenso do elemento depois que algum outro evento de toque foi acionado, como furto ou outro toque

Ian Averno
fonte
1
Para o seu snippet de código, o quadrado ainda permanece rosa depois que eu o toquei. Eu acho que você realmente não resolveu o problema nesta pergunta?
Kevin Lee
Esta solução não funciona. Primeiro, você usou o método errado para invocar um evento, você deve usar .trigger () . Segundo, não funciona no safari móvel de qualquer maneira.
XHocquet
1

Eu tenho uma boa solução que eu gostaria de compartilhar. Primeiro, você precisa detectar se o usuário está no celular assim:

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

Em seguida, basta adicionar:

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

E em CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}
Michał Reszka
fonte
2
Não funciona em dispositivos híbridos, por exemplo, PCs com tela sensível ao toque do Windows.
Cspolton 08/03/19
1

Passei pelo problema semelhante, meu aplicativo era compatível com todos os tamanhos de tela e tinha muitos efeitos de foco nos dispositivos baseados no tamanho da tela da área de trabalho / mouse, e mais tarde percebi que os dispositivos baseados em toque estavam causando uma condição conhecida como pegajosa -hover e foi um obstáculo para o aplicativo funcionar corretamente para usuários de dispositivos baseados em toque.

Estávamos fazendo uso do SCSS em nosso aplicativo. e eu defini um mixin para cuidar do dispositivo baseado em toque.

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

e, em seguida, coloquei todas as minhas aulas de css no snippet mencionado abaixo.

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

Por exemplo, tínhamos uma classe para animar um ícone, que costumava ser acionada quando passamos o mouse sobre o ícone, como você pode vê-lo no CSS, mas no dispositivo baseado em toque, ele era afetado pelo efeito de foco pegajoso e o colocava dentro de @ inclua hover-support () para garantir que o hover se aplique apenas aos dispositivos que suportam o hover.

@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
fonte
1

Aqui está um código JavaScript simples que não requer que o desenvolvedor edite CSS ou escreva novas regras CSS. Eu escrevi isso para os botões do Bootstrap com class="btn", mas funcionará com qualquer botão que tenha um nome de classe específico.

Os passos são:

  1. determinar se este é um dispositivo de toque
  2. se for, itere sobre todas as regras CSS em document.styleSheets
  3. excluir qualquer regra contendo ambos .btne:hover

A eliminação de todas as .btn :hoverregras de CSS garante que não haverá efeito de foco visual em um botão.

Etapa 1: detectar o dispositivo de toque

Verifique a consulta de mídia quanto à presença 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;
    };

Etapa 2: Excluir regras CSS contendo `btn` e`: 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;
    }

O código completo está no GitHub e npm .

Demonstração ao vivo em terrymorse.com .

terrymorse
fonte
Isso também não remove o efeito de foco nos dispositivos touchscreen com mouse / trackpad?
Jensei 31/03
@Jensei Possivelmente. As regras de focalização são removidas se o dispositivo corresponder @media (hover:none)ou quando o usuário tocar pela primeira vez na tela. Você pode experimentá-lo na página de demonstração ao vivo para ter certeza.
terrymorse 31/03
0

Você pode definir a cor de fundo no :activeestado e fornecer :focus o plano de fundo padrão.

se você definir a cor de fundo como onfocus/ontouch, o estilo de cor permanecerá assim que o :focusestado acabar.
Você precisa redefinir onblurtambém para restaurar a defaut bg quando o foco for perdido.

G-Cyrillus
fonte
Mas eu gostaria de manter o efeito de foco para os usuários de mouse.
21413 Chris
: hover e: active podem receber o mesmo CSS, está em: focus você tem o problema. Na verdade, se você definir a cor de plano de fundo via foco, o estilo de cor permanecerá assim que o foco acabar. você precisa redefinir o onlur também para restaurar o defaut bg
G-Cyrillus
0

Isso funcionou para mim: coloque o estilo de foco instantâneo em uma nova classe

.fakehover {background: red}

Em seguida, adicione / remova a classe como e quando necessário

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

Repita para os eventos touchstart e touchend. Ou os eventos que você deseja obter o resultado desejado, por exemplo, eu queria que o efeito de foco fosse alternado em uma tela de toque.

Rodney
fonte
0

Com base na resposta de Darren Cooks, que também funciona se você mover o dedo sobre outro elemento.

Consulte O elemento Localizar dedo está ativado durante um evento de toque final

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
fonte
0

Você pode tentar assim.

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
fonte
0

O que fiz até agora em meus projetos foi reverter as :hoveralterações nos dispositivos de toque:

.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 os nomes de classe e cores nomeadas apenas para fins de demonstração ;-)

z00l
fonte
0

Isso funciona perfeitamente em 2 etapas.

  1. Defina sua etiqueta corporal para ser assim <body ontouchstart="">. Não sou fã desse "hack", mas permite que o Safari no iOS reaja aos toques instantaneamente. Não sei como, mas funciona.

  2. Configure sua classe palpável assim:

    // 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;
            }
        }
    }

Você também pode remover qualquer animação da sua classe tocável. O Android Chrome parece um pouco mais lento que o iOS.

Isso também resultará na aplicação do estado ativo se o usuário rolar a página enquanto toca na sua turma.

Michael
fonte
0

Alguns dos :hover :focus :activeproblemas persistentes em dispositivos móveis podem ser causados ​​por falta de ação, <meta name="viewport" content="width=device-width">pois os navegadores tentam manipular a tela.

GEkk
fonte
0

A solução para mim foi depois que o touchend foi clonar e substituir o nó ... eu odeio fazer isso, mas até tentando repintar o elemento com offsetHeight não estava funcionando

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );
Proibição
fonte
No final, isso não funcionou para mim ... no meu caso, eu teria que clonar um ES6 inteiro, que é estendido e vários ouvintes de eventos, e isso começou a se tornar muito complicado para resolver uma coisa tão pequena.
Proibição de
0

Isso pode ser feito trocando uma classe HTML. Deve ser menos propenso a falhas do que remover todo o elemento, especialmente com links de imagens grandes etc.

Também podemos decidir se queremos que os estados de foco sejam acionados ao rolar com toque (touchmove) ou até mesmo adicionar um tempo limite para atrasá-los.

A única mudança significativa em nosso código será usar classe HTML adicional, como <a class='hover'></a>nos elementos que implementam o novo comportamento.

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 (com jQuery)

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

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

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

Exemplo

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

-

Não tenho nenhum dispositivo com o mouse e o toque para testá-lo corretamente.

Maciek Rek
fonte
0

A partir de 2020, você pode adicionar estilos de foco dentro da consulta de mídia

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

Essa consulta de mídia indica que os estilos funcionarão em navegadores que não emulam: passe o mouse para que NÃO funcione em navegadores de toque.

Dawid Świtoń
fonte