Can I disable a CSS :hover effect via JavaScript? - javascript

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.

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

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.

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.

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>

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');
});

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');
}
}
}
}
}
}

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.

Try just setting the link color:
$("ul#mainFilter a").css('color','#000');
Edit: or better yet, use the CSS, as Christopher suggested

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/

This can be realized by pure javascript easily; Try the code below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
:root {
--orange-color: #fa8e3f;
--dark-organge-color: #bd5305;
--light-color: #fff;
--dark-color: #000;
--grey-color: #f2f2f2;
--transition: all 300ms ease-in-out;
}
.quiz-options {
list-style-type: none;
margin: 1rem 0;
}
.quiz-options li {
color: var(--light-color);
background-color: var(--orange-color);
font-weight: 600;
border: 3px solid var(--orange-color);
border-radius: .5rem;
margin: .7rem 0;
padding: .4rem 1.2rem;
box-shadow: 0 4px 0 0 var(--dark-organge-color);
transition: var(--transition);
}
.quiz-options li.enable-hover-active {
cursor: pointer;
}
.quiz-options li.enable-hover-active:hover {
background-color: var(--grey-color);
color:var(--dark-color);
border-color: var(--grey-color);
box-shadow: 0 4px 0 0 #bbb;
}
.quiz-options li.enable-hover-active:active {
transform: scale(0.97);
}
button {
border: none;
border-radius: 0.5rem;
outline: 0;
font-family: 'Poppins', sans-serif;
font-size: 1.2rem;
font-weight: 600;
padding: .5rem 1rem;
margin: 0 auto;
text-transform: uppercase;
cursor: pointer;
display: block;
background-color: var(--grey-color);
color: var(--dark-color);
letter-spacing: 2px;
transition: var(--transition);
box-shadow: 0 4px 0 0 #bbb;
}
</style>
<body>
<ul class="quiz-options">
<li>option 1</li>
<li>option 2</li>
<li>option 3</li>
<li>option 4</li>
</ul>
<button type="button" id="check-answer" onclick="enableHoverActive()">Enable hover & active</button>
<script>
function enableHoverActive() {
if (document.getElementById('check-answer').textContent == 'Enable hover & active') {
document.getElementById('check-answer').textContent = 'Disable hover & active';
document.querySelectorAll('li').forEach((option) => {
option.classList.add('enable-hover-active');
});
} else {
document.getElementById('check-answer').textContent = 'Enable hover & active';
document.querySelectorAll('li').forEach((option) => {
option.classList.remove('enable-hover-active');
});
}
}
</script>
</body>
</html>
The result is as below:
when "disabled", hover and click options
when "enabled", hover and click options

Related

Hover on parent but not on child element

I have an issue where I want to activate hover state on a link when hovering on the container anywhere but except on two buttons save and close. CSS approach is preferred but if not vanilla JavaScript would be fine. Please have have look I have created a codepen
You can not trigger pseudo events. you can give it same styling when the box is hovered:
.box {
display: flex;
padding: 20px;
border-bottom: 1px solid #ccc;
transition: background .3s ease-in-out;
&:hover {
background: #f1f1f1;
a {
color: #525199;
background-color: #e6e6f0;
border-color: #525199;
}
}
This is not possible with pure CSS, as explained on the question How to style the parent element when hovering a child element?
The solution, then, is to add some Javascript to style the parent element, for example by adding a class to the parent element. A simple code snippet to achieve this with your solution, would be the following:
document.querySelectorAll('.save, .cancel').forEach(function(button) {
button.addEventListener("mouseover", function() {
button.parentNode.parentNode.className = 'box nohover';
});
button.addEventListener("mouseout", function() {
button.parentNode.parentNode.className = 'box';
});
});
And you'd then need to style the {{nohover}} class by not changing the background:
.nohover:hover {
background: none;
}
See this codepen for a working demo.
try this:
.box:hover :not(.box--right):hover a {
color: #525199;
background-color: #e6e6f0;
border-color: #525199;
}

CSS selector and border issue

I would like to achieve the following with my code:
Issue (a) Change only Click Here to be surrounded by a box.
Issue (b) The border for the box in (a) should disappear and reappear.
Currently, I face the following issues with my code:
Issue (a)
For (a), my code does not just change Click Here to be surrounded by a box. It also changes Pinterest to be surrounded by a box. I believe the issue is with selecting the top level ul but I have not succeeded in doing so.
Relevant CSS code
.cover-buttons ul:first-of-type li:nth-last-child(5) a {
color: black;
border: 1px solid black;
padding: 14px 18px!important;
font-weight: 400;
line-height: 17px;
font-size: 12px;
display: inline-block;
transition: all .2s ease;
overflow: hidden;
border-radius: 2px;
box-sizing: border-box;
list-style-type: none;
font-family: 'Varela Round', 'Poppins', sans-serif;
}
Issue (b)
For (b), I can't seem to get the box border to blink.
Relevant Javascript code
$(function(){
var count = 0, $input = jQuery('.buttons.medium.button-outlined').not('.add-review, .bookmark, .show-dropdown, .sn-share'), interval = setInterval(function() {
if ($input.hasClass('blur')) {
$input.removeClass('blur').addClass('focus'); ++count;
} else {
$input.removeClass('focus').addClass('blur');
}
if (count === 3) { clearInterval(interval); }
}, 2000);
});
Relevant CSS code
.focus {
border: 1px solid white;
}
.blur {
border: 1px solid black;
}
The strange thing about issue (b) is that it seems to work when I change the background-color as shown here: https://jsfiddle.net/75nvLs4x/12/. However, when I try to modify the border thickness it does not work.
Full script including HTML is included here: https://jsfiddle.net/75nvLs4x/14/
Thank you for your help.
Issue A
Your selector is: .cover-buttons ul li:nth-last-child(5) a this will affect any ul inside .cover-buttons. As there are two uls that have li:nth-last-child(5), both have the li:nth-last-child applied.
You can fix this by saying only the ul that's directly inside .cover-buttons and only the li directly inside that ul
.cover-buttons > ul > li:nth-last-child(5) a
Issue B
Your border issue is due to specificity - the border in the .cover-buttons ul li:nth-last-child(5) a section is more specific than just .focus so is always used. You could add !important to the border inside .focus, but that's not best practice - instead, remove the border from the main block and it works fine.
Updated fiddle: https://jsfiddle.net/75nvLs4x/18/

Setting background color with JavaScript breaks the CSS hover behavior

I'm trying to create a menu where the currently selected (clicked) element has a different background color than the other elements (I'm trying to achieve this using JavaScript). I also use the CSS :hover pseudoclass to make the hovered element stand out by highlighting it. However, I have encountered a strange problem: when I set the background color of any element with JavaScript, its CSS hover behavior no longer works. That is, I can't highlight the element by hovering it anymore. I have checked that in Firefox and Chromium. This is the case for both jQuery and plain JavaScript.
The code is below. I have simplified it a lot to narrow down the problem. First try hovering any of the menu items, then click the "Set background color" link and hover one of the menu elements again. What I expect is the element getting red (#f00) when hovered, regardless of whether the "Set background color" button was clicked or not. For jsfiddle links, go to the bottom.
Vanilla JavaScript:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
p#links a {
display: inline-block;
width: 80px;
height: 22px;
line-height: 22px;
background-color: #00f;
color: #fff;
text-decoration: none;
text-align: center;
font-family: sans-serif;
}
p#links a:hover {
background-color: #f00;
}
</style>
<title>Background color</title>
</head>
<body>
<p id="links">
Link 1
Link 2
Link 3
Link 4
</p>
Set background color
<script>
document.getElementById('setbgcolor').onclick = function() {
var p = document.getElementById('links');
var elements = p.getElementsByTagName('a');
for (var i = 0; i < elements.length; i++)
elements[i].style.backgroundColor = '#ff0';
};
</script>
</body>
</html>
jQuery:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="jquery-1.11.0.js"></script>
<style>
p#links a {
display: inline-block;
width: 80px;
height: 22px;
line-height: 22px;
background-color: #00f;
color: #fff;
text-decoration: none;
text-align: center;
font-family: sans-serif;
}
p#links a:hover {
background-color: #f00;
}
</style>
<title>Background color</title>
</head>
<body>
<p id="links">
Link 1
Link 2
Link 3
Link 4
</p>
Set background color
<script>
$('a#setbgcolor').click(function() {
$('p#links a').css('background-color', '#ff0');
});
</script>
</body>
</html>
And here are jsfiddle.net links for the purpose of convenience:
Pure JavaScript: http://jsfiddle.net/5yQFM/1/
jQuery: http://jsfiddle.net/5yQFM/
The jQuery css() method maps onto the style property which maps onto the style attribute.
Rules inside a style attribute are more specific then rules in a stylesheet, so will always come after them in the cascade.
Instead of altering the CSS on the element directly, alter it by changing the classes the element belongs to and having a pre-prepared stylesheet.
you need to use !important on hover, basically it will increase its priority.
Try this,
p#links a:hover {
background-color: #f00 !important;
}
DEMO
As Quentin said it looks like a dirty one, so in that situation we can make use of the class priority concepts.
HTML:
<a class='normal' href="#">Link 1</a>
<a class='normal' href="#">Link 1</a>
CSS:
.normal { background-color: blue; }
.abnormal{ background-color: yellow; }
.normal:hover { background-color: #f00; }
JS:
$('p#links a').attr('class', 'abnormal normal');
DEMO Non-Dirty one
How about keeping the style in CSS and not in Javascript, by adding classes ?
so the line :
elements[i].style.backgroundColor = '#ff0';
Change to
elements[i].className = 'myClassForBackgrounds';
or in the jQ version
$('p#links a').css('background-color', '#ff0');
to :
$('p#links a').addClass('myClassForBackgrounds');
That way you can set your :hover as you would normally
#links a:hover, .myClassForBackgrounds:hover { background-color:#ff0; }
Just for a more simple answer, in able to just re-enable css rules just have it toggle between the color and "", so
document.getElementById("id").style.backgroundColor = "rgb(255, 125, 15)";
would be if the element wasn't already colored via javascript.
Now, if your element was already colored the code would look like this:
document.getElementById("id").style.backgroundColor = "";
That re-enables CSS so then your selectors will work.
I encountered the same problem and solved it by doing this:
I set a onmouseover event to change the background color to what the hover color is.
I set a onmouseout event to change the background color to the default color.
This way I have set a hover event with pure javascript

Strange behavior in IE when combining click handler with CSS sibling selector

I am trying to design a menu that is triggered by clicking a button. When the user clicks the button, a click handler runs which adds a class to the button, and a CSS rule using an sibling selector makes the menu visible. It works fine in all the browsers I tested except IE 7 and 8.
In IE 7 and 8, I am experiencing these problems:
Clicking the button toggles the class but the menu doesn't appear or disappear until I move the mouse around a little bit.
The menu doesn't work at all unless I have a CSS :hover declaration for children of the menu. It doesn't matter what I put in the declaration, or if I put anything at all, but the menu does not show up without it.
Can anyone tell me why this is happening and what I can do about it? I was thinking of adding a separate class to the menu but I am wondering if there is a simpler fix or workaround. Here is my code:
<!DOCTYPE html>
<html><head>
<title>IE selector test</title>
<style type="text/css">
button {
border: outset 1px #eeeeee;
}
button.active {
border-style: inset;
}
.menu {
display: none;
border: solid 1px #888888;
}
button.active ~ .menu {
display: block;
}
.menu > :hover {
/* For some reason, the menu doesn't work at all without this declaration */
}
</style>
</head>
<body>
<button type="button" id="menuButton">Menu</button>
<div class="menu">
<div>option</div>
</div>
<script>
document.getElementById("menuButton").onclick = function() {
if (this.className) {
this.className = "";
} else {
this.className = "active";
}
};
</script>
</body>
</html>
You can also test it at http://jsfiddle.net/QKqpn/.
You can work around it by forcing page redraw:
document.body.className = document.body.className;
See http://jsfiddle.net/uGW4M/
BTW, in your case you can use + (one immediate sibling) combinator instead of more common ~ (all subsequent siblings):
button.active + .menu {/* ... */}

New <style> element not working in IE

I currently have an HTML page that has a grey BODY background. Now I would like to overwrite this and change this to white using Javascript. I also would like to change some other elements' padding and margin. I try to accomplish this using the innerHTML property.
The thing is everything is working, apart from the newly introduced element, which is not applied in IE7 or IE8. It does work in FireFox however.
<script>
// if using jQuery
$(document).ready(function() {
document.body.innerHTML = '
<style type="text/css">
body {
background-color: #FFFFFF
!important; }
#todayBirthdays, #weekendBirthdays, #noBirthdays, #todayJubileums, #weekendJubileums {
padding: 0 !important;
margin: 0 !important;
}
</style>
<div style="text-align: left; background-color: #FFFFFF">' +
document.getElementById('WebPartctl00_SPWebPartManager1_g_7118b319_c5b0_4214_a46d_27131866cde3').innerHTML +
'</div>';`
});
</script>
Can you please advise?
Many thanks!
The <style> tag is only valid inside the <head>, though some browsers may respect it in other places. If you want to change the body background or other properties with a script, use the appropriate .css() method in jQuery.
$(document).ready(function() {
$("body")css("backgroundColor", "#FFFFFF");
$("#todayBirthdays,#weekendBirthdays,#noBirthdays,#todayJubileums,#weekendJubileums").css("margin", "0");
});
Why not just
$('body').css('background-color', '#fff');
$('#todayBirthdays, #weekendBirthdays, #noBirthdays, #todayJubileums, #weekendJubileums').css('padding', 0).css('margin', 0);
See the CSS property of jQuery and also the addclass method. This is much easier than what you are doing!
$('body').css( { backgroundColor: 'value1' } );
$('#todayBirthdays, #weekendBirthdays, #noBirthdays, #todayJubileums, #weekendJubileums').css( { padding: 'valuex', margin: 'valuey' } );
Although I think you should be using addClass instead.
.myClass { /* Some styling */ }
$('#x, #y, #z').addClass(myClass);
<html>
<head>
<style type="Text/css">
body { background-color: #AAA; }
</stye>
</head>
<body>
<script type="text/javascript">
var style = document.createElement('style');
style.innerHTML = 'body { background-color: #F0F; }';
// add any other styles inside this style element
document.getElementsByTagName('head')[0].appendChild(style);
</script>
</body>
Demo of appending to the <body> and the <head>
If you are stuck on adding in an inline style which is what you asked then use the following:
$("<style type=\"text/css\"> body{background-color: #FFFFFF;} #todayBirthdays, #weekendBirthdays, #noBirthdays, #todayJubileums, #weekendJubileums { padding: 0 !important; margin: 0 !important;} </style>").appendTo("Head");
This will append your styling to the head element of the document. However in reality the better way to go if you are going to use jQuery or javascript is to just change the values of the background.
document.getElementByTagName(body).attribute(background-color)="#FFFFFF";
OR
$("body").css("background-color", "#FFFFF");

Categories