17

I need to trigger the hover pseudo class programmatically (if possible with bubbling, or i will be forced to call the change to all elements parents too). I don't have the control of the html page, so i can't change the css from :hover to .hover in order to update the class of the HTMLElement to the .hover one.

Is that possible?

Please NO JQUERY. I can't use JQuery in my project.

Thank you in advance.

UPDATE

i've created a sort of proxy for CSS loading, so now before a css is loaded it passes in my "proxy" that changes the rules from :hover to .hoverclass.

Well, now the hover effects works pretty well, but i have some serious performance issue due to the bubbling simulation of the hover.

Here is some code:

var actualHoveredElements = new Array();
var hoverAddedCount = 0;
var maxHoveredElems = 5;

function changeHover(newElement, oldElement){
    var oldHoveredElements = actualHoveredElements.slice();

    var remainingElements = setHoverForParentsOfElement(newElement, oldHoveredElements);

    for(var i = 0; i < remainingElements.length; i++){
        var notHoveredElement = remainingElements[i];
        var actualIndex = actualHoveredElements.indexOf(notHoveredElement);

        if(actualIndex > -1){
            actualHoveredElements.splice(actualIndex, 1);
        }
        notHoveredElement.classList.remove("hoverclass");
    }

    hoverAddedCount = 0;
    changeHoverTimeout = null;
}


function setHoverForParentsOfElement(element, oldHoveredElements){
    var index = -1;

    if(oldHoveredElements != "undefined" && oldHoveredElements.length > 0)
        index = oldHoveredElements.indexOf(element);

    if(index > -1){
        oldHoveredElements.splice(index, 1);
    } else {
        actualHoveredElements.push(element);
        element.classList.add("hoverclass");
    }

    if(element.tagName != "BODY" && element.tagName != "HTML"){
        if(hoverAddedCount < maxHoveredElems-1){
            hoverAddedCount ++;
            oldHoveredElements = setHoverForParentsOfElement(element.parentNode, oldHoveredElements);
        }
    }

    return oldHoveredElements;
}

As you can see, i've also tried to limit the number of hover bubbling to N, but the performance issue is still existing.

17
  • I was looking up duplicates on SO, and all I find are solutions with jQuery... +1 for you. Commented Feb 10, 2014 at 8:32
  • could you post some relevant code? Commented Feb 10, 2014 at 8:33
  • so you want to use onmouseover with onmouseout event ? Commented Feb 10, 2014 at 8:34
  • i have a programmatic simulated mouseover and mouseout events, that should also trigger hover Commented Feb 10, 2014 at 8:35
  • Perhaps stackoverflow.com/questions/2490825/… Commented Feb 10, 2014 at 8:35

2 Answers 2

5

No, you cannot use JavaScript to directly make the element register as hovered such that the :hover CSS would trigger without the mouse being over the element in question.

The closest you can get is to use JavaScript to look up the CSS rules that would be applied during a :hover and then manually apply them, as demonstrated in this gist (duplicated below for posterity's sake):

// Find all css properties for the :hover you want
var applyHoverStyle = function() {
  var div = document.getElementsByTagName("div")[0];
  var i,j, sel = /div:hover/, aProperties = [];
  for(i = 0; i < document.styleSheets.length; ++i){
    // console.log(document.styleSheets[i]);
    if(document.styleSheets[i]. cssRules !== null) {
      for(j = 0; j < document.styleSheets[i].cssRules.length; ++j){    
        if(sel.test(document.styleSheets[i].cssRules[j].selectorText)){
          aProperties.push(document.styleSheets[i].cssRules[j].style.cssText);
          // console.log(document.styleSheets[i].cssRules[j].selectorText, document.styleSheets[i].cssRules[j].style.cssText);
        }
      }
    }
  }
  //console.log(aProperties);
  div.style.cssText = aProperties.join(' ');
};
Sign up to request clarification or add additional context in comments.

Comments

0

You can try something like this, although this is not recommended:

http://jsfiddle.net/DerekL/N2GK9/

function triggerCSS(ele, selector) {
  whole: for (var i = 0; i < document.styleSheets.length; i++) {
    for (var j = 0; j < document.styleSheets[i].rules.length; j++) {
      if (document.styleSheets[i].rules[j].selectorText == selector) {
        var style = document.styleSheets[i].cssRules[j].style;
        for (var k = 0; k < style.length; k++) {
          ele.style[toCC(style[k])] = style[toCC(style[k])];
        }
        break whole;
      }

    }
  }

  function toCC(input) {
    return input.toLowerCase().replace(/-(.)/g, function(match, group1) {
      return group1.toUpperCase();
    });
  }
}

triggerCSS(document.getElementById("s"), "span:hover");
span:hover {
  color: red;
  text-decoration: underline;
}
<span id="s">ABC</span>

5 Comments

This is a terrible idea, even adding a different stylesheet and duplicating the hover styles with a class selector is better. Will hurt performance pretty much, and might be invoked pretty often... Instead of that break why not use a simple return?
@kapa - Of course I know this is a terrible idea, that's why I stated in the answer not recommended. However, the point is that it gets the job done, that's all it matter.
This is not better than adding a class in the way i said in the update of my question. Looks like even worst in performance speaking. I'm sorry, but this does not answer my question. :(
@GiuseppeLanza - Yes, if you can modify the stylesheet like what you did, then adding a class is definitely better. But remember, you didn't say I can do that in the first place so I've stick to a pure JS solution. (In fact, you explicitly said you cannot change the css from :hover to .hover .) Whether you consider this answered your question or not, I will just leave it here.
And it is a fine solution. But now i've done this "proxy" so i'm focusing on performances. :( they are not encouraging at the moment. the changing of the class of an element is damn heavy! (UIWebView performances on iPhone 4s are very bad.) Thank you anyway

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.