Calling JS Function on Button Click Blocks CSS :hover - javascript

I implement a CSS hover method on all of my buttons. It looks like this:
.button:hover { background-color: #36a39c; }
This method works perfectly fine until I click on one of my buttons. When the button is clicked, a JS function is called using this code:
<div id= "one"><button class="button" id = "b1" value="0" onclick="checker(this.id)"></button></div>
This is the JS Script:
var checker = function(id)
{
var xyz = id;
var value = document.getElementById(xyz).value
if (answerjson[value].is_right_choice==1)
{
for (var i = 1; i <=4; i++) {
document.getElementById("b"+i).style.background='#722F37';
}
document.getElementById(xyz).style.background='green';
setTimeout(function(){ alert("Correct!"); }, 100);
}
else {
for (var i = 1; i <=4; i++) {
document.getElementById("b"+i).style.background='#722F37';
}
document.getElementById(xyz).style.background='red';
setTimeout(function(){ alert("Sorry, Try Again"); }, 100);
}
}
After that script is called, my buttons no longer change color on hover. Any ideas why?

This happens because when you add background color using javascript it is added as inline styling and it overrides the css class selector because inline styling always takes more preference. You need to make a class with that color and add/remove that using javascript. e.g. make a class
.green{
background-color: green;
}
and then add it using javascript like this:
document.getElementById(xyz).className += " green";

You're setting the inline style="" attribute in your JS code.
Properties set in inline styles always override CSS selectors (except with !important), so your CSS no longer does anything.
You should add a CSS class instead of setting an inline style.

Related

Is it valid to check body background in js or is there a better way to perform the same?

bg() is a function that is triggered on click. Here is bg():
function bg() {
console.log(document.querySelector('body').style.background);
if (document.querySelector('body').style.background == "#3e4756") {
document.querySelector('body').style.background = "#ffffff";
}
if (document.querySelector('body').style.background == "#ffffff") {
document.querySelector('body').style.background = "#0000ff";
}
if (document.querySelector('body').style.background == "#0000ff") {
document.querySelector('body').style.background = "#3e4756";
}
}
So when the button is clicked, I want to keep shuffling between the background colors conditionally.
It is recommended to not use inline styles, but instead use a class.
Here is a cool solution using element.classList.replace(oldClass, newClass).
When it succeed to replace the old class with the new, it returns true, and when, we know it swapped so we simply return/exit the function.
Stack snippet
document.addEventListener('click', bg);
function bg() {
var the_body = document.querySelector('body');
if (the_body.classList.replace("first", "second")) return;
if (the_body.classList.replace("second", "third")) return;
if (the_body.classList.replace("third", "first")) return;
}
.first {
background: #3e4756;
}
.second {
background: #fff;
}
.third {
background: #00f;
}
<body class="first">
<button type="button">Toggle color</button>
</body>
Another option would be to store the classes in an attribute, and do something like this
Stack snippet
document.addEventListener('click', bg);
function bg() {
var the_body = document.querySelector('body');
var classes = the_body.dataset.swapclasses.split(','); //get the class array
var next = classes.shift(); //remove/get the first
the_body.classList.replace(classes[classes.length-1], next); //swap with the array's last
classes.push(next); //push it back at the end
the_body.dataset.swapclasses = classes.join(","); //save it
}
.first {
background: #3e4756;
}
.second {
background: #fff;
}
.third {
background: #00f;
}
<body data-swapclasses="second,third,first" class="first">
<button type="button">Toggle color</button>
</body>
And of course, if you need to use inline styles, you can use the same trick with those.
Stack snippet
document.addEventListener('click', bg);
function bg() {
var the_body = document.querySelector('body');
var classes = the_body.dataset.swapcolor.split(','); //get the color array
var next = classes.shift(); //remove/get the first
the_body.style.backgroundColor = next; //set new color
classes.push(next); //push it back at the end
the_body.dataset.swapcolor = classes.join(","); //save it
}
<body data-swapcolor="#fff,#00f,#3e4756" style="background: #3e4756;">
<button type="button">Toggle color</button>
</body>
getComputedStyle is important if the background could be set via either css style, or via the style attribute on the element tag. However, if you don't care what the background was via the CSS and you only want to control the background via the style property (like the code you have written) then you could ignore using the getComputedStyle function. Besides, when you set the background via the style attribute, it will overwrite any background value set by CSS anyway.
Here's a working example that cycles through background colors. I used a global variable bgColors for the background colors, and a starting index bgIndex. Each time, you click on the button, the toggleBg() function is called. The first time it's called, the body background is updated to the value at bgColors[0] which is #0000ff.
The next line, bgIndex is updated. It checks to see if the value is greater than the length of the array, if it is, then it sets bgIndex to 0, if it isn't then it increments it by 1.
So the next time the function is called, bgIndex is 1, so the background gets set to bgColors[1] which is #3e4756.
const bgColors = ["#0000ff", "#3e4756", "#ffffff"]
let bgIndex = 0;
function toggleBg(){
const body = document.querySelector("body");
body.style.background = bgColors[bgIndex];
bgIndex = bgIndex >= bgColors.length - 1 ? 0 : bgIndex + 1;
}
document.querySelector("#change-bg").addEventListener("click", toggleBg)
<button id="change-bg">Toggle Background</button>
.style.background will return an empty string unless the background style was set inline in the HTML (inside a style attribute on the element.)
getComputedStyle() is generally a better way to read CSS values -- but note that you're looking for backgroundColor, not background (which includes backgroundImage, backgroundRepeat, etc); and that browsers are not necessarily consistent about how they represent colors:
let theBody = document.getElementsByTagName('body')[0];
let bgColor = window.getComputedStyle(theBody).backgroundColor;
console.log(bgColor);
body {background-color: #FFC}
To find the string representation the current browser will use for a given color, you'll need to create a new temporary element with that color and then read its color value from the browser as above; then you'll have a string you can safely compare to the value read from the element you actually care about. <body> tags with no background color set are another wrinkle; they return transparent black rgba(0, 0, 0, 0) instead of white (at least on FF, Safari and Chrome on macOS; not sure if that's the same in IE or Edge). Everything is more complicated than it needs to be, this is why we drink, etc.
For your particular case it would probably be much simpler to skip all that, base your colors on specific class names, and have your function cycle through each classname on the body element.

javascript .style property of span tag in anchor tag not working as expected

I am trying to style some buttons for my website
This is my html
<div>
<a class="page_numbers"><span>100</span></a>
<a class="page_numbers"><span>2</a></span></div>
this is my css
.page_numbers{
display:table-cell;
border:solid;
padding:0px;
border-radius:100px;
width:50px;
height:50px;
text-align:center;
vertical-align:middle;
}
div {
display:table;
border-spacing:10px;
}
}
and finally this is my javascript
var obj=document.getElementsByClassName("page_numbers")
for (i in obj){
console.log(obj[i].children)
obj[i].children[0].style.color="black"
obj[i].style.borderColor="rgb(85,170,255)"
function jun(i){
obj[i].addEventListener('mouseenter',function(){obj[i].style.background="yellow";obj[i].style.color="red"},true)
//
obj[i].addEventListener('mouseleave',function(){
obj[i].style.background="white";
obj[i].style.color="rgb(12,31,22)";},true)
}
jun(i);
}
the background color changes on mouseleave and enter but not the font color...I suppose I am doing something wrong along the way or I am missing a fundamental concept
this is my jsfiddle link
http://jsfiddle.net/repzeroworld/boqv8hak/
advice please..still learning JS
Firstly, all of this should be in CSS and is trivial to do so
.page_numbers:hover
{
background-color: yellow;
}
.page_numbers:hover span
{
color: red;
}
Now the issue you are having is that on about the 4th line of your JS you explicitly set the color of the child element (the span) inside the .page_number element to be black. Now on you mouse enter you are setting the color on the page_number element, but since the child has a style applied directly to it (i.e. color: black) it does not inherit the parent style. Inline styles (i.e. style applied directly to the element with the style="" attribute, which is what JS does) always have the highest precedence. This is why it is generally not best practice to put inline styles on an element, as you have just seen, they are pretty much impossible to override. So change either the child to not have an explicit style, or on the mouse enter change the child not the parent
var obj = document.getElementsByClassName("page_numbers")
for (i in obj) {
console.log(obj[i].children)
obj[i].children[0].style.color = "black"
obj[i].style.borderColor = "rgb(85,170,255)"
function jun(i) {
obj[i].addEventListener('mouseenter', function () {
obj[i].style.background = "yellow";
obj[i].children[0].style.color = "red"
}, true)
//
obj[i].addEventListener('mouseleave', function () {
obj[i].style.background = "white";
obj[i].children[0].style.color = "rgb(12,31,22)";
}, true)
}
jun(i);
}
or
var obj = document.getElementsByClassName("page_numbers")
for (i in obj) {
console.log(obj[i].children)
obj[i].style.borderColor = "rgb(85,170,255)"
function jun(i) {
obj[i].addEventListener('mouseenter', function () {
obj[i].style.background = "yellow";
obj[i].style.color = "red"
}, true)
//
obj[i].addEventListener('mouseleave', function () {
obj[i].style.background = "white";
obj[i].style.color = "rgb(12,31,22)";
}, true)
}
jun(i);
}
but as I indicated all this should really be in CSS
You trying to change color of a instead of span
Try like this
obj[i].children[0].style.color = "red"
JSFIDDLE

Change the CSS value from a file

I have a keyboard.css file and a keyboard.js file, I am trying to change a css rule
.ui-keyboard div { font-size: 1.1em; }
I want to change the font size. is there a way to do this without using
$(".ui-keyboard div").css()?
I want to change the value before the element is rendered, I want to pass the value in the construction of an element
$('.onScreenKeyboard').keyboard({
zoomLevel: 2
});
Edit: to clarify this a bit, the goal is to have a way to change the font-size, without having to go and edit the value on the CSS. I want to create an option in the library that does this:
Inside the constructor I check for options and I change the element,
//set Zoom Level
if(o.zoomLevel){
//Change CSS Here.
}
Maybe you're looking for something like CSSStyleSheet's insertRule and deleteRule.
Here is some code I wrote a while ago to let me modify CSS rules
function CSS(sheet) {
if (sheet.constructor.name === 'CSSStyleSheet') this.sheet = sheet;
else if (sheet.constructor.name === 'HTMLStyleElement') this.sheet = sheet.sheet;
else throw new TypeError(sheet + ' is not a StyleSheet');
}
CSS.prototype = {
constructor : CSS,
add: function (cssText) {
return this.sheet.insertRule(cssText, this.sheet.cssRules.length);
},
del: function (index) {
return this.sheet.deleteRule(index);
},
edit: function (index, cssText) {
var i;
if (index < 0) index = 0;
if (index >= this.sheet.cssRules.length) return this.add( cssText );
i = this.sheet.insertRule(cssText, index);
if (i === index) this.sheet.deleteRule(i + 1);
return i;
}
};
You'd use it by giving the constructor CSS your <style> node, or it's StyleSheet directly, then using .edit with the index of the rule and the new rule you want. e.g.
// get StyleSheet
var mycss = new CSS(document.querySelector('style[src="keyboard.css"]'));
// edit rule 0
mycss.edit(0, '.ui-keyboard div { font-size: 5em; }');
Add the following css to the element, initially you wont display it until you run through your library change the style properties then display it.
.ui-keyboard div {
font-size: 1.1em;
display: none;
}
You can also change the font size without jQuery by doing something like:
[element].style.fontSize = "25px";

Cycle through div background colors onClick with Javascript

I'm trying to change a div background color to a different color depending on what the div's current color is, when the div is clicked on. The following code does not work. I've figured it has something to do with my "if" statements because it works fine if I just make them change to 1 color with no "if" statements.
<script language="JavaScript">
function setColor(blockId) {
if (document.getElementById(blockId).style.background == '#FF0000') {
document.getElementById(blockId).style.background = '#0000FF';
}else if (document.getElementById(blockId).style.background == '#0000FF') {
document.getElementById(blockId).style.background = '#999999';
}else if (document.getElementById(blockId).style.background == '#999999') {
document.getElementById(blockId).style.background = '#FF0000';
}
}
</script>
<div id="b1" style="background-color:#FF0000; height:100px; width:100px;" onClick="setColor('b1')"></div>
Increment an index to identify which background you are using from a list of backgrounds. You can store that index as a property on the element.
var backgrounds = ["#0000FF", "#999999", "#FF0000"];
function setColor(el) {
el.colorIdx = el.colorIdx || 0;
el.style.backgroundColor = backgrounds[el.colorIdx++ % backgrounds.length];
}
Also, rather than doing a lookup on that element via document.getElementById(), just pass this from the onclick handler, and your function has a reference to the element itself.
<div onclick="setColor(this)"></div>
Working demo: http://jsfiddle.net/gilly3/vPMPb/
The problem you are experiencing is because of inconcistencies in how the style.background property is understood by the browser. In some browsers style.backgroundColor (use this instead of style.background btw) will be "#FF0000" while in others it will be "#ff000" and in others "rgb(255,0,0)". so checking the string won't work for you. I suggest instead storing the color values in an array and keeping a global position variable. Every time the div is clicked, incriment the index and use the array. Similar to this:
Demo | Source
<script language="JavaScript">
var colors = ["#FF0000","#0000FF","#999999"];
var idx = 0;
function setColor(blockId) {
document.getElementById(blockId).style.backgroundColor = colors[++idx%3];
}
</script>
<div id="b1" style="background-color:#FF0000; height:100px; width:100px;" onClick="setColor('b1')"></div>
EDIT: btw, the ++idx%3 is just ++idx (increment before evaluating) and %3 (modulos 3, which is "the remainder of the value divided by 3")
It is probably not your logic. Presentation properties cannot be inferred from the DOM unless the properties are resident in a style attribute on the given DOM element node. Just supply a background color to the targeted HTML tag using a style attribute in the static HTML. Now your JavaScript and detect the background color property and performed as designed.

How do I remove :hover?

I have a small problem with a script.
I want to have a default action on :hover for clients with Javascript disabled, but for those with Javascript enabled I want another action (actually... same action, but I want to add a small transition effect).
So... How can I do this? I am using jQuery.
Apply two classes to the relvant element. one contains the hover behaviour, and one contains all the other styling.
You can then use the jquery
$(element).removeClass('hover');
method to remove the class with the hover behaviour and then apply whatever you want using
$(element).bind('mouseover', function () { doSomething(); });
$(element).bind('mouseout', function () { doSomething(); });
How about putting the :hover fall-back in a stylesheet that is only loaded if javascript is disabled?
<noscript>
<link href="noscript.css" rel="stylesheet" type="text/css" />
</noscript>
Here is a solution without hack classes:
CSS:
a {color: blue;}
a:hover {color: red;}
jQuery (uses jQueryUI to animate color):
$('a').hover(
function() {
$(this)
.css('color','blue')
.animate({'color': 'red'}, 400);
},
function() {
$(this)
.animate({'color': 'blue'}, 400);
}
);
demo
I think the best approach would be to leave the :hover behavior as a fall-back for non-javascript users and then use JQuery to create mouseover and mouseout event handlers to create a different effect for javascript-enabled users.
JQuery Javascript Library - Events/mouseover
It's a very old question but I feel the urge to tell that modernizr provides a very good way to implement these kind of fallbacks.
Just include modernizr in the head and you can do these:
.no-js a:hover {
set background color and stuff like that
for cases when no javascript is present
}
On the other hand if you want to do this the other way and only set css when js is present
.js a:hover {
set background color to default
and the text decoration
}
It is more or less the same solution as adding a hover tag to the markup, but a little more robust.
I HAVE FOUND YOUR SOLUTION
basically you start out by redefining what you did with the css hover.
(naturally you would do this by dynamically pulling the information from the style)
then do whatever you want to in jquery with mouseover/mouseout events
this allows you to keep the :hover event in your css because jquery is binding your original styles to the element. In essence disabling the :hover event.
if your css is:
a.class {
background-color: #000000;
background-position: 0 0;
}
a.class:hover {
background-color: #ffffff;
background-position: 100% -50px;
}
your jquery would be somthing like:
jQuery("a.class").each(function () {
var oldBackgroundColor = jQuery(this).css("backgroundColor");
var oldBackgroundPosition = jQuery(this).css("backgroundPosition");
jQuery(".class").css({
'backgroundColor':oldBackgroundColor,
'backgroundPosition':oldBackgroundPosition
});
})
.bind("mouseover", function() {
doSomething();
})
.bind("mouseout", function() {
doSomething();
})
You can redraw element after click
function redraw(element) {
if (!element) { return; }
let n = document.createTextNode(' ');
let disp = element.style.display; // don't worry about previous display style
element.appendChild(n);
element.style.display = 'none';
setTimeout(function(){
element.style.display = disp;
n.parentNode.removeChild(n);
}, 100); // you can play with this timeout to make it as short as possible
}
You can globally enable behavior across the entire document by using a single css rule, and then disable that rule in one statement in javascript, while installing the new event handler.
Add a class to your html body tag:
<html>
<body class="use-hover">
...
Default behavior in your css, let's say to bold links on hover:
body.use-hover a:hover
font-weight: bold
And in your js, when run will remove the default behavior and do something else:
$(function() {
$('body').removeClass('use-hover');
$('a').live('mouseover', function() {
// Do something when hovered
}).live('mouseout', function() {
// Do something after hover is lost
});
});
You could strip all :hover style rules from document.styleSheets.
Just go through all CSS styles with JavaScript and remove all rules, which contain ":hover" in their selector. I use this method when I need to remove :hover styles from bootstrap 2.
_.each(document.styleSheets, function (sheet) {
var rulesToLoose = [];
_.each(sheet.cssRules, function (rule, index) {
if (rule.selectorText && rule.selectorText.indexOf(':hover') > 0) {
rulesToLoose.push(index);
}
});
_.each(rulesToLoose.reverse(), function (index) {
if (sheet.deleteRule) {
sheet.deleteRule(index);
} else if (sheet.removeRule) {
sheet.removeRule(index);
}
});
});
I did use underscore for iterating arrays, but one could write those with pure js loop as well:
for (var i = 0; i < document.styleSheets.length; i++) {}
Vanilla JS version of Mikael Lepistö's answer
for (var i = 0; i < document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
var rulesToLose = [];
for (var j = 0; j < sheet.cssRules.length; j++) {
var rule = sheet.cssRules[j];
if (rule && rule.selectorText && rule.selectorText.indexOf(':hover') >= 0) {
rulesToLose.push(j);
}
}
// Iterate backwards to prevent pointing to the wrong index while sheet rules get deleted
for (var k = rulesToLose.length - 1; k >= 0; k--) {
sheet.deleteRule(rulesToLose[k]);
}
}

Categories

Resources