BreakHead
BreakHead

Reputation: 10672

Calling JavaScript from within CSS :hover

Is there any way that I can call a JavaScript function via css?

For example, from this :hover style:

.first-nav li a:hover,
.first-nav li.hover a {
    margin:-3px 0 -1px;
    height:30px;
    position:relative;
    background:url(../images/nav-hover.jpg) no-repeat;
}

The JavaScript function I want to call is on an anchor :hover.

Upvotes: 24

Views: 104013

Answers (7)

Ric Paton
Ric Paton

Reputation: 81

Ok, so this can be done. I was looking for something similar (overloading the CSS attr() function to include JS formatting). While looking online I found this question, so I thought I'd add a way that it is possible.

For a start, if you can, you absolutely should use addEventListener, and hook the element up to the hover event. The solution I am about to provide is cheesy and not recommended.. .. .. ..but it does answer OPs question!

(useful links at the end)

Ok, onto the code. In CSS you can have custom properties, here's an example:

<head>
 <style>
 /* sets a custom property of "--my-text-color" with the value "red" */
 :root {
   --my-text-color : "red";
 }
 /* set paragraph text not by explicit declaration but by referring to the custom property */
 p {
   color: var(--my-text-color);
 }
 /* I can change the "--my-text-color" variable, however that scope is only for this node and its children */
 p span {
   --my-text-color:"green";
   color: var(--my-text-color);
 }
 </style>
</head>
<body>
 <p> some content
  <span> more content </span>
 </p>
</body>

If you've not seen custom properties before then it'll look odd, but essentially I created a variable called --my-text-color at the :root {} level, setting it to "red". I then use that value for the color rule of <p> using var(propertyName), however within that ruleset I also redefine the --my-text-color property to "green", then use that to style the color of text of the <span> that is the child of the <p> tag.

What this demonstrates is that you can change property values based on CSS rules, however what I didn't mention was that you can query that property value using script. For example, this bit of code..

console.log( window.getComputedStyle(document.querySelector("p")).getPropertyValue("--my-text-color") );

..then you would output "red", if however you to do this..

console.log( window.getComputedStyle(document.querySelector("p span")).getPropertyValue("--my-text-color") );

..you'd get green. Ok, so what does that achieve? Well it shows that you can change property values based on CSS rules, and that you can detect the value of those properties using JS.

Finally.. the answer! I know, lots of build up, but we're there now. As :hover is a CSS rule, and OP wants to run a JS upon hover, you can set up a JS loop that will monitor a rule, and run a script when it's changed, meanwhile you use the :hover pseudo-class to set that property. Thus, when hovered the property will change, and the JS will detect it.

I can't believe I've written all this for a 14 year old problem, with a solution that nobody should ever use, but it's been a fun experiment none the less. For some working code, try this..

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Test</title>
    <style>
        /* set property at root */
        :root {
            --foo: false;
        }
        /* some minor formatting */
        .container,
        .output {
            padding: 2rem;
            border: 1px dashed #888;
            margin-bottom: 1rem;
        }
        /* upon hover, change the property to true */
        .container:hover {
            --foo: true;
        }
    </style>
    <script>
        // init the loop once the dom is in
        document.addEventListener("DOMContentLoaded", checkProperty);

        function checkProperty() {
            // get the computed style sheet for the span element
            const fooProperty = window.getComputedStyle(document.querySelector(".container")).getPropertyValue("--foo");
            // const fooProperty will equal the "--foo" property set via CSS, the :hover altering its value
            document.querySelector(".output").textContent = fooProperty;
            // I am simply outputting the fooProperty value, instead I could run a function instead 
            window.requestAnimationFrame(checkProperty);
            // this is just a simple loop, calling itself each anim frame
        }
    </script>
</head>
<body>
    <div class="container">hover me</div>
    <div class="output"></div>
</body>
</html>

If you paste that into an .html document, run it, you'll find hovering over the top div will change the text of the lower div. Instead of changing the text, I could equally run a javascript function.

Ok, so.. yeah.. it's certainly code I would never recommend, as there are far better and far easier ways to deal with a hover, but it answers OPs question even if it is somewhat cheesy.

The useful link bit...

  1. MDN - CSS Properties
  2. MDN - getPropertyValue
  3. MDN - getComputedStyle
  4. MDN - requestAnimationFrame

Upvotes: 0

Alain Reve
Alain Reve

Reputation: 321

It's both an aesthetic quality and, as such, it should be handled with CSS and a functional quality which should, as such, be handled with html and javascript.

And there is a very simple way to call a function on page load from within html:

<body onload="myFunction()">

Upvotes: -1

ant
ant

Reputation: 22948

You can call it from javascript(it does the same thing). Below is the code on how to do it on JS:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("a").hover(function(){
        myFunctionInvoke();
    });
});
</script>

or if you have particular anchor in mind just change the selector

Upvotes: 3

N3Cr0M0rPh
N3Cr0M0rPh

Reputation: 31

Actually. Yes you can. Just use javascript: in the background-url like this:

<STYLE type="text/css">BODY{background:url("javascript:yourFunction();")}</STYLE>

Not entirely sure if this will work though.

Cheers!

Upvotes: -2

Cornelius
Cornelius

Reputation: 338

Because it's more logical to do it from CSS.

If one wants to make links click on hover, it's an aesthetic quality and should be handled with CSS. For example:

#header_menu li a:hover{
    color:white;
    js:click();
}

Upvotes: -1

T.J. Crowder
T.J. Crowder

Reputation: 1075309

No, you can't trigger JavaScript from CSS directly.

What you can do is use CSS selectors to find the elements you want to watch in this way, and then watch for mouse events. The standard events are mouseover and mouseout, but they can be a bit tricky to work with because they bubble (you get mouseout, for instance, whenever the mouse leaves any descendant element). With appropriate logic, though, they're not to bad to work with, and in fact if you have lots of these, you probably want to use mouseover and mouseout rather than the alternative below because you can set them on just a parent container and then work out which descendant element is involved, which can be simpler in some cases (and more complicated in others).

IE provides mouseenter and mouseleave which are much easier to work with because they don't bubble, but (of course) IE-specific. These are so handy that frameworks are starting to support them even in browsers that don't; Prototype and jQuery provide them, for instance, and I wouldn't be too surprised if some other frameworks do as well. jQuery also provides the handy hover function, which would be very close to what you want:

// jQuery
$(".first-nav li a").hover(
    function(event) {
        // The mouse has entered the element, can reference the element via 'this'
    },
    function (event) {
        // The mouse has left the element, can reference the element via 'this'
    }
 );

...which is really just a shortcut for setting up mouseenter and mouseleave handlers, but still, wonderfully concise.

In Prototype it's quite similar:

// Prototype
$$(".first-nav li a")
    .invoke("observe", "mouseenter", function(event) {
        // The mouse has entered the element, can reference the element via 'this'
    })
    .invoke("observe", "mouseleave", function(event) {
        // The mouse has left the element, can reference the element via 'this'
    });

(OT: In both cases, I've used anonymous inline function expressions just to avoid giving the impression you have to use named functions. I always recommend using named functions in production code, though.)

Upvotes: 28

Quentin
Quentin

Reputation: 944198

No.

(Well, Microsoft Expressions and Mozilla Bindings might allow it, but both are proprietary and should be avoided)

Assign your event handlers from JavaScript. Libraries such as YUI and jQuery allow you to pick elements to apply them to using CSS selectors. Event delegation allows you to handle events on elements without having to assign to each one explicitly (which is handy if you are adding them to the document after it loads).

Upvotes: 5

Related Questions