Estou escrevendo um site que deve ser usado em desktops e tablets. Quando ele está sendo visitado a partir de um desktop, quero que as áreas clicáveis da tela se iluminem com:hover
efeitos (cor de fundo diferente, etc.) Com um tablet, não há mouse, então não quero nenhum efeito de foco.
O problema é que, quando toco em algo no tablet, o navegador evidentemente tem algum tipo de "cursor invisível do mouse" que se move para o local onde toquei e o deixa lá - então o que acabei de tocar acende-se com um efeito de foco até que eu toque em outra coisa.
Como posso obter os efeitos de foco quando estou usando o mouse, mas suprimi-los quando estou usando a tela sensível ao toque?
Caso alguém esteja pensando em sugerir isso, não quero usar a detecção de user agent. O mesmo dispositivo pode ter uma tela sensível ao toque e um mouse (talvez não tão comum hoje, mas muito mais no futuro). Não estou interessado no dispositivo, estou interessado em como ele está sendo usado atualmente: mouse ou touchscreen.
Eu já tentei ligar os touchstart
, touchmove
, e touchend
eventos e chamando preventDefault()
em todos eles, o que faz suprimir o "cursor do mouse invisível" por algum tempo; mas se eu tocar rapidamente para frente e para trás entre dois elementos diferentes, depois de alguns toques, ele começará a mover o "cursor do mouse" e acender os efeitos de foco de qualquer maneira - é como se o meu preventDefault
nem sempre fosse respeitado. Não vou aborrecê-lo com os detalhes, a menos que seja necessário - nem tenho certeza se essa é a abordagem certa a se tomar; se alguém tem uma solução mais simples, sou todo ouvidos.
Editar: isso pode ser reproduzido com CSS padrão do bog :hover
, mas aqui está uma reprodução rápida para referência.
<style>
.box { border: 1px solid black; width: 150px; height: 150px; }
.box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>
Se você passar o mouse sobre qualquer uma das caixas, terá um fundo azul, o que eu desejo. Mas se você tocar em qualquer uma das caixas, também obterá um fundo azul, que é o que estou tentando evitar.
Eu também postei um exemplo aqui que faz o acima e também engancha os eventos de mouse do jQuery. Você pode usá-lo para ver que a TAP eventos também irá disparar mouseenter
, mousemove
e mouseleave
.
fonte
Respostas:
Deduzo da sua pergunta que o efeito de foco muda o conteúdo da sua página. Nesse caso, meu conselho é:
touchstart
emouseenter
.mouseleave
,touchmove
eclick
.Como alternativa, você pode editar sua página para que não haja alteração de conteúdo.
fundo
Para simular um mouse, navegadores como o Webkit mobile disparam os seguintes eventos se um usuário tocar e soltar um dedo na tela de toque (como o iPad) (fonte: Touch And Mouse em html5rocks.com):
touchstart
touchmove
touchend
mouseover
mouseenter
mouseover
,mouseenter
oumousemove
evento muda o conteúdo da página, os seguintes eventos não são disparados.mousemove
mousedown
mouseup
click
Não parece possível simplesmente dizer ao navegador da web para pular os eventos do mouse.
O que é pior, se um evento de mouseover altera o conteúdo da página, o evento de clique nunca é disparado, conforme explicado no Safari Web Content Guide - Handling Events , em particular a figura 6.4 em One-Finger Events . O que exatamente é uma "mudança de conteúdo" dependerá do navegador e da versão. Descobri que para iOS 7.0, uma mudança na cor de fundo não é (ou não é mais?) Uma mudança de conteúdo.
Solução Explicada
Para recapitular:
touchstart
emouseenter
.mouseleave
,touchmove
eclick
.Observe que não há nenhuma ação em
touchend
!Isso funciona claramente para eventos de mouse:
mouseenter
emouseleave
(versões ligeiramente melhoradas demouseover
emouseout
) são disparados e adicionam e removem o foco.Se o usuário realmente for
click
um link, o efeito de foco também será removido. Isso garante que ele seja removido se o usuário pressionar o botão Voltar no navegador da web.Isso também funciona para eventos de toque: na inicialização do toque, o efeito de foco é adicionado. É '' 'não' '' removido no touchend. Ele é adicionado novamente
mouseenter
, e como isso não causa alterações no conteúdo (ele já foi adicionado), oclick
evento também é disparado e o link é seguido sem a necessidade de o usuário clicar novamente!O atraso de 300 ms que um navegador tem entre um
touchstart
evento eclick
é realmente bem utilizado porque o efeito de foco será mostrado durante esse curto período.Se o usuário decidir cancelar o clique, um movimento do dedo fará isso normalmente. Normalmente, isso é um problema, pois nenhum
mouseleave
evento é disparado e o efeito de foco permanece no lugar. Felizmente, isso pode ser facilmente corrigido removendo o efeito de foco emtouchmove
.É isso aí!
Observe que é possível remover o atraso de 300ms, por exemplo, usando a biblioteca FastClick , mas isso está fora do escopo desta questão.
Soluções alternativas
Encontrei os seguintes problemas com as seguintes alternativas:
touchend
: Isso seguirá o link incorretamente, mesmo que o usuário queira apenas rolar ou aplicar zoom, sem a intenção de clicar no link.touchend
que é usada como uma condição se em eventos subsequentes do mouse para evitar mudanças de estado naquele ponto no tempo. A variável é redefinida no evento de clique. Veja a resposta de Walter Roman nesta página. Esta é uma solução decente se você realmente não quer um efeito de foco nas interfaces de toque. Infelizmente, isso não funciona se atouchend
for disparado por outro motivo e nenhum evento de clique for disparado (por exemplo, o usuário rolou ou fez zoom) e, subsequentemente, tentar seguir o link com um mouse (ou seja, em um dispositivo com mouse e interface de toque )Leitura Adicional
mouseover
oumousemove
.fonte
touchend
vez detouchstart
na maioria dos casos, para evitar ações de gatilho imediatamente quando o usuário está tentando rolar para cima ou para baixo em uma página. Ainda acontecerá, mas é menos provável que distraia ou confunda (presumindo que seja algo inofensivo, como exibir um rótulo, não algo que o usuário precise saber que aconteceu)Talvez não pense nisso tanto como suprimir efeitos de foco para telas sensíveis ao toque, mas como adicionar efeitos de foco para eventos de mouse?
Se você deseja manter os
:hover
efeitos em seu CSS, pode especificar estilos diferentes para mídias diferentes:Só que infelizmente existem muitos dispositivos móveis que ignoram isso e apenas usam as regras da tela. Felizmente, muitos dos navegadores de celular / tablet mais recentes suportam algumas consultas de mídia mais sofisticadas:
Portanto, mesmo se a parte "tela" ou "dispositivo portátil" for ignorada, a "largura máxima" fará o truque para você. Você pode simplesmente supor que qualquer coisa com uma tela menor que 800 pixels deve ser um tablet ou telefone, e não usar efeitos de foco. Para os raros usuários que estão usando um mouse em um dispositivo de baixa resolução, eles não veriam os efeitos de foco, mas seu site estaria bem de outra forma.
Leituras adicionais sobre consultas de mídia? Existem muitos artigos sobre isso online - aqui está um: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet
Se você deslocar os efeitos de foco de seu CSS e aplicá-los com JavaScript, você pode vincular especificamente a eventos de mouse e / ou novamente, você pode apenas fazer algumas suposições apenas com base no tamanho da tela com o "problema" de pior caso sendo que alguns o usuário que usa o mouse perde os efeitos de foco.
fonte
preventDefault()
, isso às vezes suprime os eventos do mouse, mas como eu disse na minha pergunta, não é confiável.Escrevi o seguinte JS para um projeto recente, que era um site para desktop / celular / tablet que tem efeitos de foco que não deveriam aparecer ao toque.
O
mobileNoHoverState
módulo abaixo possui uma variávelpreventMouseover
(declarada inicialmente comofalse
), que é definida paratrue
quando um usuário dispara otouchstart
evento em um elemento$target
,.preventMouseover
é então definido de volta parafalse
sempre que omouseover
evento for disparado, o que permite que o site funcione como pretendido se um usuário estiver usando a tela sensível ao toque e o mouse.Sabemos que
mouseover
está sendo acionado depoistouchstart
por causa da ordem em que estão sendo declaradosinit
.O módulo é então instanciado mais adiante na linha:
fonte
Eu realmente queria uma
css
solução pura para isso, já que espalhar uma solução javascript pesada em todas as minhas visualizações parecia uma opção desagradável. Finalmente encontrei o @ media.hover consulta , que pode detectar "se o mecanismo de entrada principal permite que o usuário passe o mouse sobre os elementos." Isso evita dispositivos de toque onde "pairar" é mais uma ação emulada do que uma capacidade direta do dispositivo de entrada.Por exemplo, se eu tiver um link:
Então, posso estilizá-lo com segurança apenas
:hover
quando o dispositivo o suportar facilmente com istocss
:Enquanto a maioria dos navegadores modernos oferece suporte a consultas de recursos de mídia de interação, alguns navegadores populares , como o IE e o Firefox , não. No meu caso, isso funciona bem, já que eu pretendia apenas oferecer suporte ao Chrome no desktop e ao Chrome e Safari no celular.
fonte
Minha solução é adicionar a classe css hover-active à tag HTML e usá-la no início de todos os seletores CSS com: hover e remover essa classe no primeiro evento touchstart.
http://codepen.io/Bnaya/pen/EoJlb
JS:
HTML:
CSS:
fonte
'ontouchstart' in window
. por exemploif ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
O que fiz para resolver o mesmo problema é ter uma detecção de recurso (uso algo como este código ), ver se onTouchMove está definido e, se estiver, adiciono a classe css "touchMode" ao corpo, caso contrário, adiciono " desktopMode ".
Então, toda vez que algum efeito de estilo se aplica apenas a um dispositivo de toque, ou apenas a um desktop, a regra css é anexada com a classe apropriada:
Edit : Esta estratégia, é claro, adiciona alguns caracteres extras ao seu css, então se você estiver preocupado com o tamanho do css, você pode pesquisar as definições touchMode e desktopMode e colocá-los em arquivos diferentes, para que possa servir css otimizado para cada dispositivo tipo; ou você pode alterar os nomes das classes para algo muito mais curto antes de começar.
fonte
Certo, eu só tive um problema semelhante, mas consegui corrigi-lo com consultas de mídia e CSS simples. Tenho certeza de que estou quebrando algumas regras aqui, mas está funcionando para mim.
Basicamente, tive que pegar um aplicativo enorme feito por alguém e torná-lo responsivo. Eles usaram jQueryUI e me pediram para não mexer em nenhum de seus jQuery, então eu estava restrito a usar CSS sozinho.
Quando eu pressionava um de seus botões no modo touchscreen, o efeito de foco disparava por um segundo antes que a ação do botão tivesse efeito. Veja como eu consertei.
fonte
No meu projeto, resolvemos esse problema usando https://www.npmjs.com/package/postcss-hover-prefix e https://modernizr.com/ Primeiro, pós-processamos os arquivos css de saída com
postcss-hover-prefix
. Ele adiciona.no-touch
para todas ashover
regras de css .css
torna-se
Em tempo de execução
Modernizr
adiciona automaticamente classes css ahtml
tags como estaEsse pós-processamento de css plus Modernizr desativa o foco para dispositivos de toque e habilita para outros. Na verdade, essa abordagem foi inspirada no Bootstrap 4, como eles resolvem o mesmo problema: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile
fonte
Você pode acionar o
mouseLeave
evento sempre que tocar em um elemento da tela sensível ao toque. Aqui está uma solução para todas as<a>
tags:fonte
Iv encontrou 2 soluções para o problema, o que implica que você detecte o toque com modernizr ou outra coisa e defina uma classe de toque no elemento html.
Isso é bom, mas não tem muito suporte :
Mas isso tem um suporte muito bom :
Funciona perfeitamente para mim, faz com que todos os efeitos de foco sejam como quando você toca em um botão, ele acende, mas não acaba com erros como o efeito de foco inicial para eventos de mouse.
Detectando o toque em dispositivos sem toque, acho que a modernizr fez o melhor trabalho:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.jsEDITAR
Eu encontrei uma solução melhor e mais simples para este problema
Como determinar se o cliente é um dispositivo de toque
fonte
Ver seu CSS pode ajudar, pois parece um problema um tanto estranho. Mas de qualquer maneira, se estiver acontecendo e tudo mais estiver certo, você pode tentar mudar o efeito de foco para javascript (você pode usar jquery também). Simplesmente, vincule-se ao evento mouseover ou, melhor ainda, ao evento mouseenter e acenda seu elemento quando o evento for disparado.
Confira o último exemplo aqui: http://api.jquery.com/mouseover/ , você poderia usar algo semelhante para registrar quando o evento for disparado e partir daí!
fonte
mouseenter
; sem dados. Tocar move o "cursor invisível do mouse", então ele disparamouseenter
emousemove
(emouseleave
quando você toca em outro lugar).Se você gosta de usar JavaScript, pode usar o Modernizr em sua página. Quando a página carrega, um navegador sem tela de toque terá a classe '.no-touch' adicionada à tag html, mas para um navegador com tela de toque, a tag html terá a classe '.touch' adicionada à tag html .
Em seguida, é simplesmente um caso de verificar se a tag html tem a classe no-touch antes de decidir adicionar os ouvintes do mouseenter e da licença do mouse.
Para um dispositivo com tela sensível ao toque, os eventos não terão ouvintes, portanto, você não terá efeito de foco quando tocar.
fonte
.touch
e.no-touch
. Reescrever sua resposta em CSS junto com o Modernizer,html.no-touch .box:hover {background-color: "#0000ff"}
e não definir nada parahtml.touch .box:hover
deve resolver , já que o OP está apenas tentando evitar:hover
s móveis .Em um projeto que fiz recentemente, resolvi esse problema com o recurso de eventos delegados do jQuery. Ele procura por certos elementos usando um seletor jQuery e adiciona / remove uma classe CSS para esses elementos quando o mouse está sobre o elemento. Parece funcionar bem, tanto quanto fui capaz de testá-lo, que inclui o IE10 em um notebook com capacidade de toque executando o Windows 8.
editar: esta solução, é claro, requer que você altere seu CSS para remover os seletores ": hover" e contemple com antecedência quais elementos você deseja que sejam "pairáveis".
Se você tiver muitos elementos em sua página (como vários milhares), pode ficar um pouco lento, porque essa solução captura eventos de três tipos em todos os elementos da página e, em seguida, faz seu trabalho se o seletor corresponder. Chamei a classe CSS de "mouseover" em vez de "hover", porque não queria que nenhum leitor de CSS lesse ": hover" onde escrevi ".hover".
fonte
Aqui está minha solução: http://jsfiddle.net/agamemnus/g56aw709/-- código abaixo.
Tudo o que se precisa fazer é converter o seu ": hover" em ".hover" ... é isso! A grande diferença entre isso e o resto é que também funcionará em seletores de elementos não singulares, como
.my_class > *:hover {
.fonte
Inclua Modernizr em sua página e defina seus estados de foco como este:
fonte
Olá, pessoa do futuro, você provavelmente deseja usar a consulta de mídia
pointer
e / ouhover
. Ahandheld
consulta de mídia foi descontinuada.fonte
Experimente esta solução jquery de 2019 fácil, embora já exista há algum tempo;
adicione este plugin ao head:
src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"
adicione isso a js:
$("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements
algumas variações sugeridas para isso são:
Notas
Referências:
https://code.jquery.com/ui/
https://api.jquery.com/category/selectors/jquery-selector-extensions/
fonte