Posso desativar um efeito CSS: hover via JavaScript?

99

Estou tentando evitar que o navegador use o :hoverefeito do CSS, via JavaScript.

Eu defini os estilos ae a:hoverem meu CSS, porque quero um efeito de foco, se JS não estiver disponível. Mas se JS estiver disponível, quero substituir meu efeito de foco CSS por um mais suave (usando o plugin de cores jQuery, por exemplo).

Eu tentei isso:

$("ul#mainFilter a").hover(
     function(e){ e.preventDefault(); ...do my stuff... }, 
     function(e){ e.preventDefault(); ...do my stuff... });

Eu também tentei com return false;, mas não funciona.

Aqui está um exemplo do meu problema: http://jsfiddle.net/4rEzz/ . O link deve desaparecer sem ficar cinza.

Conforme mencionado por fudgey, uma solução alternativa seria redefinir os estilos de foco usando, .css()mas eu teria que substituir todas as propriedades especificadas no CSS (veja aqui: http://jsfiddle.net/raPeX/1/ ). Estou procurando uma solução genérica.

Alguém sabe como fazer isso?

PS: Não quero sobrescrever todos os estilos que defini para o foco.

meo
fonte

Respostas:

136

Não existe uma solução genérica de JavaScript puro, infelizmente. JavaScript não é capaz de desligar o :hoverpróprio estado CSS .

Você pode tentar a seguinte solução alternativa. Se você não se importa em mexer um pouco no seu HTML e CSS, isso evita que você tenha que redefinir todas as propriedades CSS manualmente via JavaScript.

HTML

<body class="nojQuery">

CSS

/* Limit the hover styles in your CSS so that they only apply when the nojQuery 
class is present */

body.nojQuery ul#mainFilter a:hover {
    /* CSS-only hover styles go here */
}

JavaScript

// When jQuery kicks in, remove the nojQuery class from the <body> element, thus
// making the CSS hover styles disappear.

$(function(){}
    $('body').removeClass('nojQuery');
)
Paul D. Waite
fonte
5
Gosto mais desta solução do que das soluções noscript porque funciona quando o CSS está inteiramente contido em arquivos externos e também funciona durante o carregamento da página, se o CSS carregar primeiro, mas o JS só carregar mais tarde. Usar jQuery para "melhorar progressivamente" as coisas geralmente resulta em páginas que não funcionam bem se você clicar nas coisas antes de terminar de carregar. Mesmo com um navegador rápido em um link rápido eu vejo muito isso.
Sr. Brilhante e Novo 安 宇
@Sr. Brilhante e novo: concordo, gosto mais disso do que da minha solução também! Não sei por que não notei a elegância deste antes ...
Josh
3
“Gosto mais desta solução do que das soluções noscript porque funciona quando o CSS está inteiramente contido em arquivos externos” - o mesmo acontece com a <noscript>solução. Você acabou de colocar <link>tags dentro do seu <noscript>, em vez de <style>tags. Minha solução permite que você mantenha tudo dentro de um arquivo de folha de estilo em vez de vários arquivos.
Paul D. Waite
não é exatamente o que eu estava procurando, mas acho que essa solução é o melhor compromisso! Obrigado a todos vocês
meo
você também pode copiar o mesmo estilo com um nome diferente e usando jquery selecionar todos os elementos com aquela classe e remover a classe e substituir pela classe de cópia.
chepe263
14

Use uma segunda classe que tenha apenas o foco atribuído:

HTML

 <a class="myclass myclass_hover" href="#">My anchor</a>

CSS

 .myclass { 
   /* all anchor styles */
 }
 .myclass_hover:hover {
   /* example color */
   color:#00A;
 }

Agora você pode usar Jquery para remover a classe, por exemplo, se o elemento foi clicado:

JQUERY

 $('.myclass').click( function(e) {
    e.preventDefault();
    $(this).removeClass('myclass_hover');
 });

Espero que esta resposta seja útil.

Kai Noack
fonte
3
mais 1. não é ortodoxo, mas resolve o problema de uma forma bastante sublime.
Jim Tollan
11

Você pode manipular as próprias folhas de estilo e regras de folha de estilo com javascript

var sheetCount = document.styleSheets.length;
var lastSheet = document.styleSheets[sheetCount-1];
var ruleCount;
if (lastSheet.cssRules) { // Firefox uses 'cssRules'
    ruleCount = lastSheet.cssRules.length;
}
else if (lastSheet.rules) { / /IE uses 'rules'
    ruleCount = lastSheet.rules.length;
}
var newRule = "a:hover { text-decoration: none !important; color: #000 !important; }";
// insert as the last rule in the last sheet so it
// overrides (not overwrites) previous definitions
lastSheet.insertRule(newRule, ruleCount);

Tornar os atributos importantes e fazer com que seja a última definição CSS deve substituir qualquer definição anterior, a menos que uma seja mais especificamente direcionada. Você pode ter que inserir mais regras nesse caso.

Stephen P
fonte
1
Ou você pode colocar todas as regras noscript em uma folha de estilo e, em seguida, desabilitar a folha de estilo do javascript.
Sean Hogan
2
Ou colocar sua <link>tag de folha de estilo noscript dentro de um <noscript>elemento? Isso funcionaria, certo?
Paul D. Waite
1
Ou exclua a regra "ofensiva": developer.mozilla.org/en/DOM/stylesheet.deleteRule
RoToRa
1
Até o IE5 pode fazer isso. Seu método é chamado de maneira diferente, mas deve funcionar: msdn.microsoft.com/en-us/library/ms531195%28v=vs.85%29.aspx . Não verifiquei outros navegadores, mas acho que todos os navegadores modernos implementam o padrão.
RoToRa
No Firefox eu receboError: The operation is insecure.
Alex W
11

Isso é semelhante à resposta de aSeptik, mas e quanto a essa abordagem? Envolva o código CSS que você deseja desativar usando JavaScript nas <noscript>tags. Dessa forma, se o javaScript estiver desligado, o CSS :hoverserá usado, caso contrário, o efeito JavaScript será usado.

Exemplo:

<noscript>
<style type="text/css">
ul#mainFilter a:hover {
  /* some CSS attributes here */
}
</style>
</noscript>
<script type="text/javascript">
$("ul#mainFilter a").hover(
     function(o){ /* ...do your stuff... */ }, 
     function(o){ /* ...do your stuff... */ });
</script>
Josh
fonte
4

Usei o not()operador CSS e a addClass()função jQuery . Aqui está um exemplo, quando você clica em um item da lista, ele não pairará mais:

Por exemplo:

HTML

<ul class="vegies">
    <li>Onion</li>
    <li>Potato</li>
    <li>Lettuce</li>
<ul>

CSS

.vegies li:not(.no-hover):hover { color: blue; }

jQuery

$('.vegies li').click( function(){
    $(this).addClass('no-hover');
});
ColdTuna
fonte
3

Eu usaria CSS para evitar que o evento: hover alterasse a aparência do link.

a{
  font:normal 12px/15px arial,verdana,sans-serif;
  color:#000;
  text-decoration:none;
}

Este CSS simples significa que os links sempre estarão pretos e não sublinhados. Não posso dizer pela pergunta se a mudança na aparência é a única coisa que você deseja controlar.

Christopher Altman
fonte
é bom que haja um efeito: hover se JS não estiver disponível em um cliente. Mas se for preciso sobrescrevê-lo. Eu configurei uma classe: hover no meu css, só quero desabilitá-la.
meo
@meo: Você não pode desativar as classes CSS psuedo, mas pode substituí-las definindo todos os estilos de link para ter a mesma aparência / parâmetros. Esta resposta e minha resposta fazem isso, apenas de maneiras diferentes.
Mottie
3

Eu recomendo substituir todas as :hoverpropriedades para :activequando você detectar que o dispositivo suporta toque. Basta chamar essa função ao fazer isso como touch().

function touch() {
  if ('ontouchstart' in document.documentElement) {
    for (var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
      var sheet = document.styleSheets[sheetI];
      if (sheet.cssRules) {
        for (var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
          var rule = sheet.cssRules[ruleI];

          if (rule.selectorText) {
            rule.selectorText = rule.selectorText.replace(':hover', ':active');
          }
        }
      }
    }
  }
}
Shobhit Sharma
fonte
Funciona muito bem para mim. Obrigado!
Inversão de
1

Tente apenas definir a cor do link:

$("ul#mainFilter a").css('color','#000');

Editar: ou melhor ainda, use o CSS, como sugeriu Christopher

Mottie
fonte
jsfiddle.net/raPeX fiz um exemplo. Funciona, mas é meio estúpido fazer isso. eu teria que recuperar todos os valores CSS e adicioná-los como estilo? Deve haver uma maneira melhor. Eu não quero fazer isso. mas 1 para a dica
meo
Olá, meo, não, meu código acima estava direcionado a um link específico, pois é isso que achei que você queria. Você poderia generalizar mais simplesmente usando em avez de ul#mainFilter ase é isso que você quer dizer, ou está dizendo que cada link na página tem uma cor diferente?
Mottie
Atualizei sua demonstração, com comentários, para mostrar o que quero dizer: jsfiddle.net/raPeX/2
Mottie
Eu já entendi, obrigado. Mas o problema é que não há apenas a mudança de cor em meu foco, às vezes é o fundo, a borda, às vezes até a altura da linha. É por isso que seria mais fácil para mim apenas evitar que o hover, den substitua todos os efeitos do hover.
meo
Patch parcial para esta ideia: Você poderia criar css uma regra que seleciona para a.jsOverride:hoverque substitua todas as características do css, então o js teria apenas que adicionar essa jsOverrideclasse a todos os links quando a página carregar ...
grossvogel
1

Na verdade, uma outra maneira de resolver isso seria sobrescrever o CSS com insertRule.

Ele permite injetar regras CSS em uma folha de estilo nova / existente. No meu exemplo concreto, seria assim:

//creates a new `style` element in the document
var sheet = (function(){
  var style = document.createElement("style");
  // WebKit hack :(
  style.appendChild(document.createTextNode(""));
  // Add the <style> element to the page
  document.head.appendChild(style);
  return style.sheet;
})();

//add the actual rules to it
sheet.insertRule(
 "ul#mainFilter a:hover { color: #0000EE }" , 0
);

Demonstração com meu exemplo original de 4 anos: http://jsfiddle.net/raPeX/21/

meo
fonte