1

Here's the jsfiddle that I've been trying to debug:

http://jsfiddle.net/Neoheurist/x57fkzng/

HTML

<div id="birthday">Surprise Party</div>
<p></p>
<button onclick="blue()">Blue</button>
<button onclick="red()">Red</button>

<script>
function blue()
{
    element=document.getElementById("birthday");

    element.innerHTML="Happy";

    element.style.background="blue";
    element.style.width="150px";
    element.style.opacity="1.0";
    element.style.transition="width 2s,background 15s,opacity 2s";
}

function red()
{
    element=document.getElementById("birthday");

    element.innerHTML="Birthday";

    element.style.background="red";
    element.style.width="300px";
    element.style.opacity="0.0";
    element.style.transition="width 2s,background 4s,opacity 6s";
}
</script>

CSS

div
{
    width:100px;
    height:50px;
    background:blue;
    transition:width 2s,opacity 2s,background 15s;
}

div:hover
{
    width:200px;
    background:green;
    opacity:0.25;
    transition-timing-function:linear;
    transition:width 2s,background 4s,opacity 6s;
}

Questions:

Why does clicking a button disable div:hover?

How can I prevent this from happening?

Neoheurist
  • 3,183
  • 6
  • 37
  • 55

3 Answers3

3

It's because HTML style attributes override element selectors in a css file. Any property set directly in an HTML style attribute will automatically be used over any property set in any css selector declaration.

Style attributes are much more specific than tag selectors (that's why they aren't recommended for use in fact).

According to the inspector in webkit this also includes the :hover state, so any inline style will stop a hover state from working.

You could use important, tempting as it might be, but that's not a good idea, because it takes the current problem with specificity that you're having and amplifies it even further, leading to a specificity nightmare. The only way to over-ride !important is with more !important, further down the document, or by using more specific selectors (like IDs) or longer chains of selectors and !important and so on, you can see how this can be horrible to maintain. Also any js that adds style to the HTML directly won't work either.

The best solution is to use javascript to add and remove css classes to trigger your changes. This will solve your problem as all your classes will have manageable specificity.

#birthday.blue {
    background: blue;
    width: 150px;
    opacity: 1.0;
    transition: width 2s,background 15s,opacity 2s;
}

#birthday.red {    
    background: red;
    width: 300px;
    opacity: 0.0;
    transition: width 2s,background 4s,opacity 6s;
}

Then make sure the hover state is defined for all the combinations, so any class will :hover. This is not possible with inline styles.

#birthday:hover,
#birthday.blue:hover,
#birthday.red:hover
{
    width: 200px;
    background: green;
    opacity: 0.2;
    transition-timing-function: linear;
    transition: width 2s,background 4s,opacity 6s;
}

I've put together a jsfiddle that demos this. I've used JQuery, for the sake of getting a demo together quickly and their addClass() method is great. Good effort to use pure js, it's a good habit to get into; this question will elaborate on how to add and remove classes in javascript

Plus; as an added bonus, you'll also have all your style in your style file and all your functionality in your javascript, which is better separation of concerns and makes the site styling DRYer and easier to re-use elsewhere in the project (you don't have styles stuck is js that you can't easily add elsewhere, which you copy instead, then try to change in one place and not the other ... we all do it, or our colleagues do!).

[Seen as I've brought up the subject of specificity you might also be interested to know that IDs are also pretty bad for that and unnecessary in style files]

Community
  • 1
  • 1
Toni Leigh
  • 4,830
  • 3
  • 22
  • 36
  • 1
    I like the technique - and to this end I forked and embellished your example (giving it a zork theme) - using pure javascript https://jsfiddle.net/Neoheurist/gkhst24j/ Theoretically I have succeeded in following your example. – Neoheurist Jun 11 '15 at 22:01
  • @Neoheurist it's a pretty standard technique, try it with [keyframe animations](http://www.smashingmagazine.com/2011/05/17/an-introduction-to-css3-keyframe-animations/) and you can make some really cool stuff happen – Toni Leigh Jun 11 '15 at 22:53
  • @Neoheurist - here we are from the article, all on click with a single class :-) http://www.impressivewebs.com/demo-files/css3-animated-scene/ – Toni Leigh Jun 11 '15 at 23:43
2

You could make the div:hover attributes all !important like so:

div:hover{
   width:200px !important;
}

However I've heard you'd want to avoid !important if possible, but this does what you want...

Thomas Mol
  • 31
  • 2
0

You can also use

document.addEventListener('DOMContentLoaded', function () {
    var storedStyles;
    var elem = document.getElementById("birthday");
    elem.addEventListener('mouseenter', function () {
        if (elem.hasAttribute('style')) {
            storedStyles = elem.attributes.style.value;
            elem.removeAttribute('style');
        }
    });

    elem.addEventListener('mouseleave', function () {
        if (storedStyles) {
            elem.setAttribute('style', storedStyles);
        } else {
            storedStyles = null;
        }
    });
 });

and clear all styles on mouse enter restoring hover styles precendence and setting back your inline styles on mouse leave

devconcept
  • 3,665
  • 1
  • 26
  • 40
  • in this case you would also have to re-trigger you other styles on mouse leave in order to create the reverse of a hover effect ... – Toni Leigh Jun 11 '15 at 20:13
  • @ToniLeigh Sure, and you have to store those styles somewere before removing. Using classes is the proper aproach to this problem. I added this answer because filling you CSS with !important doesn't feel right. I dont know why that answer was marked as accepted. – devconcept Jun 11 '15 at 20:22
  • @devconcept unaccepted the answer you've referenced... I was being overly eager to get something working... – Neoheurist Jun 11 '15 at 21:03