: pseudoclasse ativa não funciona no safari móvel

109

No Webkit no iPhone / iPad / iPod, a especificação do estilo de uma pseudo classe: active para uma <a>tag não é acionada quando você toca no elemento. Como posso fazer com que isso seja acionado? Código de exemplo:

<style> 
a:active { 
    background-color: red;
}
</style>
<!-- snip -->
<a href="#">Click me</a>
Jesse Rusak
fonte

Respostas:

238
<body ontouchstart="">
    ...
</body>

Aplicado apenas uma vez, ao contrário de cada elemento de botão, parecia corrigir todos os botões da página. Alternativamente, você pode usar esta pequena biblioteca JS chamada ' Fastclick '. Ele acelera os eventos de clique em dispositivos de toque e também cuida desse problema.

wilsonpage
fonte
19
Não é suficiente simplesmente adicionar ontouchstartsem o =""? (HTML5)
feklee
2
Para futuros leitores, postei uma demonstração aqui: http://jsbin.com/EjiWILe/3/ . Verifique a funcionalidade do seu dispositivo iOS.
mhulse
6
Você pode explicar por que aplicou um ouvinte vazio ao corpo? Como isso funciona?
Maurizio Battaghini
2
Eu estava usando: focus, e isso funciona para isso também. Obrigado pelo Magic.
TecBrat
Estou obtendo o congelamento de página no iOS 9.1 e 9.3 usando este método ... essas versões tinham um bug do js, ​​mas ainda têm 0,5% de usuários nesses sistemas operacionais
Ruskin
55

Como outras respostas afirmaram, o iOS Safari não aciona a :activepseudo-classe a menos que um evento de toque seja anexado ao elemento, mas até agora esse comportamento tem sido "mágico". Encontrei esta pequena sinopse na Biblioteca do Desenvolvedor Safari que explica isso (grifo meu):

Você também pode usar a -webkit-tap-highlight-colorpropriedade CSS em combinação com a definição de um evento de toque para configurar os botões para se comportarem de forma semelhante à área de trabalho. No iOS, os eventos do mouse são enviados tão rapidamente que o estado inativo ou ativo nunca é recebido. Portanto, o :activepseudo-estado é acionado apenas quando há um evento de toque definido no elemento HTML - por exemplo, quando ontouchstart é definido no elemento da seguinte maneira:

<button class="action" ontouchstart=""
        style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
    Testing Touch on iOS
</button>

Agora, quando o botão é tocado e mantido pressionado no iOS, o botão muda para a cor especificada sem a cor cinza transparente ao redor aparecer.

Em outras palavras, definir um ontouchstartevento (mesmo se estiver vazio) é dizer explicitamente ao navegador para reagir a eventos de toque.

Na minha opinião, esse é um comportamento falho e provavelmente remonta ao tempo em que a web "móvel" era basicamente inexistente (dê uma olhada nas capturas de tela na página vinculada para ver o que quero dizer), e tudo era orientado para o mouse. É interessante notar que outros navegadores móveis mais recentes, como no Android, exibem muito bem o pseudo-estado `: active 'no toque, sem quaisquer hacks como o que é necessário para iOS.

(Observação: se você quiser usar seus próprios estilos personalizados no iOS, também pode desativar a caixa cinza translúcida padrão que o iOS usa no lugar do :activepseudo-estado usando a -webkit-tap-highlight-colorpropriedade CSS, conforme explicado na mesma página vinculada acima .)


Depois de alguma experimentação, a solução esperada de definir um ontouchstartevento no <body>elemento para o qual todos os eventos de toque borbulham não funciona totalmente. Se o elemento estiver visível na janela de visualização quando a página for carregada, ele funcionará bem, mas rolar para baixo e tocar em um elemento que estava fora da janela de visualização não aciona o :activepseudo-estado como deveria. Então, em vez de

<!DOCTYPE html>
<html><body ontouchstart></body></html>

anexe o evento a todos os elementos em vez de depender do evento borbulhando no corpo (usando jQuery):

$('body *').on('touchstart', function (){});

No entanto, não estou ciente das implicações de desempenho disso, então tome cuidado.


EDIT: Há uma falha séria com esta solução: até mesmo tocar em um elemento enquanto rola a página irá ativar o :activepseudo estado. A sensibilidade é muito forte. O Android resolve isso introduzindo um pequeno atraso antes que o estado seja mostrado, que é cancelado se a página for rolada. À luz disso, sugiro usar isso apenas em elementos selecionados. No meu caso, estou desenvolvendo um aplicativo da web para uso em campo que é basicamente uma lista de botões para navegar nas páginas e enviar ações. Como a página inteira é basicamente composta de botões em alguns casos, isso não funcionará para mim. No entanto, você pode definir o :hoverpseudo-estado para preencher isso. Depois de desativar a caixa cinza padrão, funciona perfeitamente.

user128216
fonte
6
Ótima explicação do porquê e não apenas do como ! Obrigado!
coderfin
6
Aprovado por dar compreensão aos devotos, não apenas uma receita "mágica". Isso é infinitamente mais informativo do que os outros; obrigado por escrever isso para nós.
user508633
Votado para explicação detalhada + advertências. Esta deve ser a resposta correta.
Master of Ducks de
39

Adicione um manipulador de eventos para ontouchstart em sua tag <a>. Isso faz com que o CSS funcione magicamente.

<a ontouchstart="">Click me</a>
Jesse Rusak
fonte
3
Desculpe, esta é uma resposta antiga, mas por que funciona? Não me importo "magicamente" como motivo, mas se você pudesse explicar por que funciona, eu adoraria ler mais detalhes.
mhulse
1
@mhulse também adoraria saber por quê.
Jesse Rusak
Ha! Estamos no mesmo barco. Vou tentar fazer uma pesquisa e postar aqui um link para documentos (semi) oficiais sobre o assunto. Eu amo que essa técnica funcione, só me pergunto por quê?
mhulse
7

Isso funciona para mim:

document.addEventListener("touchstart", function() {},false);

Nota: se você fizer este truque, também vale a pena remover a cor de realce de toque padrão que o Mobile Safari aplica usando a seguinte regra CSS.

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

Em 8 de dezembro de 2016, a resposta aceita ( <body ontouchstart="">...</body>) não funciona para mim no Safari 10 (iPhone 5s): Esse hack só funciona para os elementos que estavam visíveis no carregamento da página.

No entanto, adicionando:

<script type='application/javascript'>
  document.addEventListener("touchstart", function() {}, false);
</script>

para headque funcione da maneira que desejo, com a desvantagem de que agora todos os eventos de toque durante a rolagem também acionam o :activepseudo-estado nos elementos tocados. (Se isso for um problema para você, considere a :hover solução alternativa do FighterJet .)

Todos
fonte
4
//hover for ios
-webkit-tap-highlight-color: #ccc;

Isso funciona para mim, adicione ao seu CSS no elemento que você deseja destacar

Olho vermelho
fonte
3

Você está usando todas as pseudo-classes ou apenas uma? Se você estiver usando pelo menos dois, verifique se eles estão na ordem certa ou todos quebram:

a:link
a:visited
a:hover
a:active

..naquela ordem. Além disso, se você estiver apenas usando: active, adicione um: link, mesmo se não estiver estilizando-o.

tahdhaze09
fonte
ótima dica sobre a importância da ordem ao definir o estilo das pseudo classes.
brianarpie
1

Publiquei uma ferramenta que deve resolver esse problema para você.

Superficialmente, o problema parece simples, mas na realidade o comportamento de toque e clique precisa ser personalizado bastante extensivamente, incluindo funções de tempo limite e coisas como "o que acontece quando você rola uma lista de links" ou "o que acontece quando você pressiona o link e depois mova o mouse / dedo para longe da área ativa "

Isso deve resolver tudo de uma vez: https://www.npmjs.com/package/active-touch

Você precisará ter seus: estilos ativos atribuídos à classe .active ou escolher seu próprio nome de classe. Por padrão, o script funcionará com todos os elementos do link, mas você pode sobrescrevê-lo com sua própria matriz de seletores.

Comentários e contribuições honestas e úteis, muito apreciadas!

Dmitrizzle
fonte
2
Essa biblioteca adiciona 9 ouvintes de evento (não passivos) a cada elemento de link, mas não chama removeEventListener - isso seria uma grande falha para aplicativos de página única, eu acho
Drenai
1
Obrigado Ryan. Não apoio ou uso esse código há mais de um ano; Eu vou tirar. Depois de alguma reflexão e experimentação, mudei o design do aplicativo em vez de tentar forçar interações não levadas em conta ou pensadas pelos navegadores.
dmitrizzle
1

Para aqueles que não querem usar o ontouchstart, você pode usar este código

<script>
 document.addEventListener("touchstart", function(){}, true);
</script>
Noob Dev
fonte
1

Tentei essa resposta e suas variantes, mas nenhuma parecia funcionar de maneira confiável (e não gosto de depender de 'mágica' para coisas como essa). Então, fiz o seguinte, que funciona perfeitamente em todas as plataformas, não apenas na Apple:

  1. Declarações CSS renomeados que se usaram :activepara .active.
  2. Fez uma lista de todos os elementos afetados e adicionou pointerdown/mousedown/touchstartmanipuladores de eventos para aplicar a .activeclasse e pointerup/mouseup/touchendmanipuladores de eventos para removê-los. Usando jQuery:

    let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
    let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
    
    let clickableThings = '<comma separated list of selectors>';
    $(clickableThings).on(controlActivationEvents,function (e) {
        $(this).addClass('active');
    }).on(controlDeactivationEvents, function (e) {
        $(this).removeClass('active');
    });

Isso foi um pouco tedioso, mas agora tenho uma solução que é menos vulnerável a rupturas entre as versões do Apple OS. (E quem precisa de algo assim?)

daffinm
fonte
Acho que fornece uma resposta à pergunta. Parece não haver uma maneira confiável de fazer a pseudo classe: active funcionar no Safari móvel. Mas isso pode ser emulado de forma confiável usando a solução que forneci. Eu fiz isso no meu aplicativo e funciona perfeitamente em todas as plataformas. E eu adicionei o código a título de esclarecimento.
daffinm
0

Uma solução é confiar em, em :targetvez de :active:

<style> 
a:target { 
    background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>

O estilo será acionado quando a âncora for direcionada pelo url atual, que é robusto mesmo em dispositivos móveis. A desvantagem é que você precisa de outro link para limpar a âncora no url. Exemplo completo:

a:target { 
    background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>

rgmt
fonte
-3

Não 100% relacionado a esta questão, mas você também pode usar css sibling hack para fazer isso

HTML

<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>

SCSS

input {
    &:checked + label {
      background-color: red;
    }
  }

Se você gostaria de usar puro html / css tooltip

span {
  display: none;
}
input {
    &:checked ~ span {
      display: block;
    }
  }
Seeliang
fonte
-6
<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="utf-8">

<title></title>

<style>
        a{color: red;}
        a:hover{color: blue;}
</style>
</head>

<body>

        <div class="main" role="main">
                <a href="#">Hover</a>
        </div>

</body>
</html>
TroyM
fonte
1
De acordo com o FAQ, assinaturas e autopromoção não são permitidas.
LittleBobbyTables - Au Revoir