102

I’m trying to prevent the browser from using the :hover effect of the CSS, via JavaScript.

I have set the a and a:hover styles in my CSS, because I want a hover effect, if JS isn’t available. But if JS is available, I want to overwrite my CSS hover effect with a smoother one (using the jQuery color plugin for example.)

I tried this:

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

I also tried it with return false;, but it does not work.

Here is an example of my problem: http://jsfiddle.net/4rEzz/. The link should just fade without getting gray.

As mentioned by fudgey, a workaround would be to reset the hover styles using .css() but I would have to overwrite every single property, specified in the CSS (see here: http://jsfiddle.net/raPeX/1/ ). I am looking for a generic solution.

Does anyone know how to do this?

PS: I do not want to overwrite every style i have set for the hover.

meo
  • 28,823
  • 17
  • 81
  • 121

9 Answers9

138

There isn’t a pure JavaScript generic solution, I’m afraid. JavaScript isn’t able to turn off the CSS :hover state itself.

You could try the following alternative workaround though. If you don’t mind mucking about in your HTML and CSS a little bit, it saves you having to reset every CSS property manually 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
  • 89,393
  • 53
  • 186
  • 261
  • 5
    I like this solution better than the noscript solutions because this works when the CSS is entirely contained in external files, and it also works during page load, if the CSS loads first but the JS doesn't load until later. Using jQuery to "progressively enhance" things often results in pages that don't work well if you click on stuff before it's finished loading. Even with a fast browser on a fast link I see this a lot. – Mr. Shiny and New 安宇 May 05 '10 at 19:25
  • @Mr. Shiny and New: I agree, I like this better than my solution also! I'm not sure why I didn't notice the elegance of this one before... – Josh May 05 '10 at 21:29
  • 3
    “I like this solution better than the noscript solutions because this works when the CSS is entirely contained in external files” — so does the ` – Paul D. Waite May 06 '10 at 11:02
  • its not exactly what i was looking for but i think this solution is the best compromise! Thx to all of you – meo May 10 '10 at 17:23
  • you can also copy the same style with a different name and using jquery select all the elements with that class and remove the class and replace with the copy class. – chepe263 Apr 11 '12 at 20:47
  • @chepe263: I’m not quite sure how that would help. The OP said he didn’t want to overwrite all the hover styles in his stylesheet. – Paul D. Waite Apr 12 '12 at 07:51
  • Great work. Just to note: If you are detecting touch screen to disable some hover functions, make sure you don't forget windows 8 users. – Patrick Jan 28 '13 at 12:59
  • @Patrick: sure, but we weren't talking about detecting touch screens at all here. We were purely talking about removing CSS `:hover` styles via JavaScript. – Paul D. Waite Jan 28 '13 at 13:49
16

Use a second class that has only the hover assigned:

HTML

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

CSS

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

Now you can use Jquery to remove the class, for instance if the element has been clicked:

JQUERY

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

Hope this answer is helpful.

Avatar
  • 11,039
  • 8
  • 98
  • 167
11

You can manipulate the stylesheets and stylesheet rules themselves with 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);

Making the attributes !important and making this the very last CSS definition should override any previous definition, unless one is more specifically targeted. You may have to insert more rules in that case.

Stephen P
  • 13,259
  • 2
  • 40
  • 61
  • 1
    Or you could put all the noscript rules in one stylesheet and then disable the stylesheet from javascript. – Sean Hogan May 05 '10 at 00:04
  • 2
    Or put your noscript stylesheet `` tag inside a ` – Paul D. Waite May 05 '10 at 00:11
  • 1
    Or delete the "offending" rule: https://developer.mozilla.org/en/DOM/stylesheet.deleteRule – RoToRa May 05 '10 at 13:56
  • 1
    Even IE5 can do it. It's method is called differently, but it should work: http://msdn.microsoft.com/en-us/library/ms531195%28v=vs.85%29.aspx . I haven't checked other browsers, but I would guess all modern browsers implement the standard. – RoToRa May 06 '10 at 10:15
  • In Firefox I get `Error: The operation is insecure.` – Alex W May 15 '13 at 19:46
11

This is similar to aSeptik's answer, but what about this approach? Wrap the CSS code which you want to disable using JavaScript in <noscript> tags. That way if javaScript is off, the CSS :hover will be used, otherwise the JavaScript effect will be used.

Example:

<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
  • 10,711
  • 11
  • 62
  • 103
4

I used the not() CSS operator and jQuery's addClass() function. Here is an example, when you click on a list item, it won't hover anymore:

For example:

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');
});
Caio Mar
  • 1,465
  • 3
  • 19
  • 32
3

I would use CSS to prevent the :hover event from changing the appearance of the link.

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

This simple CSS means that the links will always be black and not underlined. I cannot tell from the question whether the change in the appearance is the only thing you want to control.

Christopher Altman
  • 4,690
  • 2
  • 28
  • 48
  • its good that there is a :hover effect if JS is not avalible on a client. But if it is i need to overwrite it. I have set a:hover class in my css, is just want to disable it. – meo May 02 '10 at 19:04
  • @meo: You can't disable the CSS psuedo classes, but you can override it by setting all the link styles to have the same appearance/parameters. Both this answer and my answer do this, just in different ways. – Mottie May 03 '10 at 14:17
3

I'd recommend to replace all :hover properties to :active when you detect that device supports touch. Just call this function when you do so as 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
  • 564
  • 1
  • 8
  • 18
1

Actually an other way to solve this could be, overwriting the CSS with insertRule.

It gives the ability to inject CSS rules to an existing/new stylesheet. In my concrete example it would look like this:

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

Demo with my 4 years old original example: http://jsfiddle.net/raPeX/21/

meo
  • 28,823
  • 17
  • 81
  • 121
1

Try just setting the link color:

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

Edit: or better yet, use the CSS, as Christopher suggested

Mottie
  • 74,638
  • 25
  • 119
  • 230
  • http://jsfiddle.net/raPeX/ i have made an example. It works but its kind of stupid to do that. i would have to retrieve every CSS value and add them as style? There must be a better way. I don't want to do that. but +1 for the hint – meo May 03 '10 at 15:31
  • Hi Meo, no no, my code above was targeting a specific link as that is what I thought you wanted. You could generalize it more by just using `a` instead of `ul#mainFilter a` if that is what you mean, or are you saying every link on the page is a different color? – Mottie May 03 '10 at 20:06
  • I've updated your demo, with comments, to show you what I mean: http://jsfiddle.net/raPeX/2/ – Mottie May 03 '10 at 20:22
  • ive got that already thank you. But the problem is, there is not just the color changing on my hover, sometimes its the background to, the border, sometimes even the line-height. Thats why it would be easier for me to just prevent the hover, den to overwrite every single hover effect. – meo May 04 '10 at 08:28
  • Partial patch for this idea: You could create css a rule that selects for `a.jsOverride:hover` that overrides all of the css characteristics, so the js would just have to add that `jsOverride` class to all the links when the page loads... – grossvogel May 05 '10 at 00:11