6

I want to copy all :hover classes into .hoverid classes where id is the index of the element (or any other way to create unqiue hover classes names).

So, my idea was somehow to iterate through all elements on the page which have a :hover defined and clone that class into .hoverid. This way I could trigger the hover effect on any element I want like this:

$('#element').addClass('hover'+$(this).id);

So my question(s) actually are:

  1. How to iterate through elements which have a ":hover" defined?
  2. How to clone that class into another class?

Fiddle to try your solutions: http://jsfiddle.net/kLt2P/

XCS
  • 27,244
  • 26
  • 101
  • 151

3 Answers3

3

JS and CSS are completely independent of one another. In other words, you cannot access the properties of a CSS class through JS, though you can access the CSS properties of an element, as JS acts on elements.

Solution
You can use some hackish solutions to solve this, but the best solution would probably be to create a "reverse extend" method in jQuery. In other words, you would have to write a method that does the opposite of .extend() by taking two arrays and returning all of the properties in the second that are different from or non-existent in the first array. This is actually not as difficult as it sounds.

What you would do next is take each of the elements on the page and run your "reverse extend" method on them. You would have to pass the array returned by calling the .css() method on the element when not hovering as your first parameter, and the array returned when calling the .css() method on the element while hovering, as your second parameter.

If the resulting array is not empty, then the element does have a :hover class defined (or a JS applied :hover class). Here's the kicker: the resulting array will have all of the properties of the :hover class!

A Note on Capturing Hover:
You can capture the hover by binding mousein, mouseenter, and hover. I recommend using mousein and mouseenter and using a variable flag to indicate if the other was done. As they may run concurrently in some browsers, this may require a little extra funkiness with binding and unbinding the handlers, using the .on and .off methods, to prevent duplicate clones of the class. This implementation should give you support in all major browsers (IE6-10, Safari, Opera, Chrome, and Firefox).
Update: I was incorrect about being able to trigger the pseudo-hover state (sorry about that) - this is impossible through JS. However, you can use this solution for capturing the hover, and then clone the class' properties when it is first hovered. You can then add the hovered element to a jQuery array, which you will use to ensure that you do not look at the same element more than once (using .not). The downside of this is that you will not be able to prevent cloning a :hover pseudo-class more than once, if the same :hover class is assigned to more than one element.


Let me know if you have any questions on this. Good luck! :)

Zachary Kniebel
  • 4,686
  • 3
  • 29
  • 53
  • Sorry about that, Cristy, I was mistaken. Can you tell me when you the classes will be cloned? In other words, do you have to clone them upfront, or can they be cloned as you go, i.e. cloned as each element is hovered? – Zachary Kniebel Jan 29 '13 at 20:45
  • It doesn't matter as long as I can trigger the hover, so I can clone the class when the element is hovered only. – XCS Jan 30 '13 at 21:58
  • This is where it gets ugly: what you will want to do, then, is get the CSS styles for every element, ahead of time using the `.css()` method, and store them in an object (note that you may have to use some vanilla JS here to store some node information so that you can properly identify the element later - you may also want to use JSON here). You will have to implement the handlers that I described in my solution, and the "reverse extend" method, and will call the latter whenever an element is hovered. For more on this, see my **Update**, below the "Note on Capturing Hover". – Zachary Kniebel Jan 31 '13 at 00:20
  • See my comment on the accepted answer. It seems that it can be magically done by simply replacing `:hover` with `.hover` as javascript has access and can dynamically change the stylesheets on the page. – XCS Jan 31 '13 at 00:54
3

You could actually use a library like JSCSSP and parse all CSS files ( $('link['rel="stylesheet"']).attr('href') ) somehow and create classes based on that. Another way would be to parse it yourself with some basic regex. No ideas for now - but i'll try something.

You could use webworkers for performance too.

http://www.glazman.org/JSCSSP/

ioan
  • 751
  • 1
  • 9
  • 26
2

CSS already does this work for you. In your CSS, put

.hoverid:hover
{
    // your hover styling.
}

To put the "hovering" effect on any element dynamically, then, you would either generate it with class="hoverid" or

$('#element').addClass('hoverid');

hoverid is such an unusual name that I think you mean to have different hovering styles, in which case, just have different CSS classes defining the semantics of the style and why it would behave differently.

For example:

.definition:hover { }
.syntax:hover { }
.useroption:hover { }

And apply the proper semantic CSS class to any element you want. Voila! You'll get proper dynamic results based on the types of your elements.

Understanding that you want to be able to add this class and trigger it "dynamically", you can define the CSS like:

.definitionhover, .definition:hover { }

and then have access to the class through .addClass("definitionhover") while retaining CSS's automated hover formatting.

See http://jsfiddle.net/kLt2P/1/ for how to create a naming convention that lets you do this on individual IDs.

See http://jsfiddle.net/kLt2P/5/ for how to do this without changing the CSS. Note: this parses the actual css so you need as a selector the exact value as defined in the file.

See http://jsfiddle.net/kLt2P/14/ to put both methods together by creating a dynamic stylesheet.

Plynx
  • 11,341
  • 3
  • 32
  • 33
  • Yes, but I want to be able to apply the styles defined here using javaScript. And `:hover` can not be triggered using javaScript (it can somehow but it only works in firefox and not as expected) – XCS Jan 29 '13 at 19:24
  • @Cristy see http://stackoverflow.com/questions/4347116/trigger-css-hover-with-js . In your CSS, define the hover class with another name so you can do both. – Plynx Jan 29 '13 at 19:28
  • I can not modify the CSS file directly. So... I am actually asking for a method to do those changes using javascript. – XCS Jan 29 '13 at 19:30
  • You have to achieve the same result you did in your fiddle BUT, without changing anything in the CSS window. – XCS Jan 29 '13 at 19:34
  • UpVoted. Now, how could I activate/deactivate the hover effect? – XCS Jan 29 '13 at 20:23
  • 1
    @GamsterKatalin Thanks, this was a fun puzzler. – Plynx Jan 29 '13 at 21:04
  • Now... the problem is that an element can be styled by multiple selectors, so I should somehow select all the styles that have selectors that match the current element. – XCS Jan 30 '13 at 22:01
  • @Cristy id selectors must be unique, so long as you must have #id:hover you can update the selector test from `classes[x].selectorText==className` to something like `className.test(classes[x].selectorText)` and pass in regular expressions instead of strings, such as `/\#blah\:hover/` – Plynx Jan 30 '13 at 22:13
  • I have no control over how the CSS file is structured and has to work on any CSS file format, containing different selectors... – XCS Jan 30 '13 at 22:19
  • @Cristy Iterate all styles in every stylesheet for `/\:hover/` and change `:hover` to `._hover` in your dynamic stylesheet. Then you can just `.addClass("_hover")` and any rules that would have applied to the element will also apply to your dynamic _hover style. – Plynx Jan 30 '13 at 22:30
  • 1
    @Cristy Nice! Seemed almost impossible yesterday, but never say never! – Plynx Jan 31 '13 at 00:05
  • @Plynx Yes it really did. But it now seems so trivial :). Thanks for your answer! – XCS Jan 31 '13 at 00:51