Change link color on div hover

K

Krys

Hopefully a simple request:

I have navigation as a css styled ul, all contained within a larger
DIV. I would like to have the color of all the <a> elements change on
mouseover the outside div, but I can't seem to get the syntax right.

Here's what isn't working:

<div id="navigation" onmouseover="document.getElementById('navlist
a').style.color='#000';">
<ul id="navlist">
<li><a href="#">Link1</a></li>
<li><a href="#">Link2</a></li>
<li><a href="#">Link3</a></li>
<li><a href="#">Link4</a></li>
<li><a href="#">Link5</a></li>
<li><a href="#">Link6</a></li>
</ul>
</div>

Any help greatly appreciated!
 
R

rf

Krys said:
Hopefully a simple request:

I have navigation as a css styled ul, all contained within a larger
DIV. I would like to have the color of all the <a> elements change on
mouseover the outside div, but I can't seem to get the syntax right.

Here's what isn't working:

<div id="navigation" onmouseover="document.getElementById('navlist
a').style.color='#000';">
<ul id="navlist">
<li><a href="#">Link1</a></li>
<li><a href="#">Link2</a></li>
<li><a href="#">Link3</a></li>
<li><a href="#">Link4</a></li>
<li><a href="#">Link5</a></li>
<li><a href="#">Link6</a></li>
</ul>
</div>

Any help greatly appreciated!

No javascript required, just a little bit of CSS:

#navigation:hover a {color: #000;}
 
S

SAM

Le 6/7/09 6:55 AM, rf a écrit :
No javascript required, just a little bit of CSS:

#navigation:hover a {color: #000;}

Not with all browsers ...


<div id="navigation"
onmouseover="this.className='over';"
onmouseout="this.className='';">


CSS:
====
#navigation.over #navlist a { color: #000 }
 
T

Thomas 'PointedEars' Lahn

Please attribute quotation(s) to their author(s).
vvvvvvvvvvv said:
Awesome - thanks!

Except that it doesn't work with IE 6, and not properly in all cases with
IE 7, and IE 8 in Compatibility Mode (I did not care about its "Standards"
Mode yet), which some of us still need to support.

As far as I am concerned, the reliable implementation of non-`a'
element-related hover effects (like here) in Internet Explorer is a long and
sad story, so far without a happy ending. You can start by reading here:

<http://pointedears.de/scripts/test/dom/hoverMe/>

In particular, I had to notice recently that even those related target
checks (thanks to the person here who recommended performing them) are
insufficient when it comes to hovering over a `li' that has padding and
contains `h2' and `p' with margins (that is, div>li>h2 and div>li> p).

I'm not sure if the following is the last word on the subject, but it WFM as
good as I currently think it can. I couldn't avoid yet some blinking when
moving the pointer from one 1.5em-heighted line of the `p' to another line,
and from the `p' to the `h2'.

var jsx = {
// ...

object: {
// ...

/**
* Retrieves the value of a property.
*
* @param o : Object
* @param sProperty : string
* @param aDefault : mixed
* @return mixed
* @throw
* <code>jsx.object.</code>{@link PropertyError} if the property
* does not exist or has the <code>undefined</code> value, and
* <var>aDefault</var> was not provided
*/
getProperty: function(o, sProperty, aDefault) {
if (typeof o[sProperty] != "undefined")
{
return o[sProperty];
}

/* default value not passed */
if (arguments.length < 3)
{
jsx.throwThis(this.PropertyError, sProperty);
}

return aDefault;
},
};

jsx.dom = {
// ...

isAncestor:
/**
* @param o : Element
* @param o2 : Element
* @type boolean
* @return <code>true</code>, if <code>o</code> refers to an element
* object representing the ancestor element of the element
* represented by the object <code>o2</code> refers to;
* <code>false</code> otherwise.
*/
function(o, o2) {
if (o && o2)
{
while ((o2 = o2.parentNode))
{
if (o2 == o) return true;
}
}

return false;
},

/**
* Adds a CSS class name to the <code>class</code> attribute of
* an {@link Element}.
*
* @param o : Element
* @param sClassName : string
* @param bRemove : boolean
* If the class name is already there, and this argument is
* <code>true</code>, all instances of it are removed first.
* If the class is there and this argument is <code>false</code>,
* exit without changing anything. The default is <code>false</code>,
* which is more efficient.
*/
addClassName:
function(o, sClassName, bRemove) {
var rx = new RegExp("(^\\s*|\\s+)" + sClassName + "(\s*$|(\\s))");

if (bRemove)
{
this.removeClassName(o, sClassName);
}
else if (rx.test(o.className))
{
return;
}

if (/\S/.test(o.className))
{
o.className += " " + sClassName;
}
else
{
o.className = sClassName;
}
},

/**
* Removes all occurences of a CSS class name from the
* <code>class</code> attribute of an {@link Element}.
*
* @param o : Element
* @param sClass : string
*/
removeClassName:
function(o, sClassName) {
var curClassNames = o.className;
var newClassNames = curClassNames.replace(
new RegExp("(^\\s*|\\s+)" + sClassName + "(\s*$|(\\s))", "g"),
"$3");
o.className = newClassNames;
}

// ...
};

/**
* Custom hover function. Adds/removes the "hover" class
* from the class attribute of the primary target.
*
* @param e : Event
* @param o : Element
* @return boolean
*/
function hoverFunc(e, o)
{
var jsx_object = jsx.object;
var jsx_dom = jsx.dom;

if (o)
{
var
relatedTarget = jsx_object.getProperty(e, "relatedTarget", null),
currentTarget = jsx_object.getProperty(e, "currentTarget", null);

if (!(relatedTarget && currentTarget))
{
currentTarget = jsx_object.getProperty(e, "srcElement", null);

if (e.type == "mouseover")
{
relatedTarget = jsx_object.getProperty(e, "fromElement", null);
//var isRelated = jsx_dom.isAncestor(currentTarget, relatedTarget);
}
else if (e.type == "mouseout")
{
relatedTarget = jsx_object.getProperty(e, "toElement", null);
var isRelated = jsx_dom.isAncestor(
o, jsx_object.getProperty(e, "fromElement", null));
}
}

if (!relatedTarget || !currentTarget || currentTarget == relatedTarget
|| isRelated)
{
return false;
}

if (e.type == "mouseover")
{
/* TODO: Does this even make sense? */
// var me = arguments.callee;
// if (typeof me.lastHover != "undefined" && me.lastHover != o)
// {
// /*
// * For quick pointer movements:
// * Leave only one element in hover-on state
// */
// me({type: "mouseout", currentTarget: o}, me.lastHover);
// }
//
// hoverFunc.lastHover = o;

jsx_dom.addClassName(o, "hover");
}
else if (e.type == "mouseout")
{
jsx_dom.removeClassName(o, "hover");
}
}

return true;
}

Questions, comments, solutions anyone?


Ceterum censeo Internet Explorer esse delendam.

PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
<http://pointedears.de/scripts/test/dom/hoverMe/>

In particular, I had to notice recently that even those related target
checks (thanks to the person here who recommended performing them) are
insufficient when it comes to hovering over a `li' that has padding and
contains `h2' and `p' with margins (that is, div>li>h2 and div>li> p).

That's div > ul > li > h2 + p, of course.
 
T

Thomas 'PointedEars' Lahn

kangax said:
^^^^ ^^^ ^ ^
Are those "extra" \s* meant to speed things up? Otherwise, they seem
unnecessary.

They are meant to make it more reliable (a class name is already there if it
is followed by optional whitespace followed by the end of input, or followed
by mandatory whitespace), however it really should be "\\s*$" because of the
string.
As well as those parens around last \s.

Unnecessary indeed, just copy-pasted from removeClassName() where they make
sense.
On a side note, have you considered caching regex objects? I know that
`new RegExp` is a pretty expensive operation in at least Firefox, so
caching could speed things up substantially.

Considering the possible change in ES 5, and the cost involved looking up
the RegExp, that does not seem to make sense.


PointedEars
 
J

Jorge

Just to clarify what I meant:

var addClassName = (function(){
   var cache = {};
   return function(element, className) {
     var re = cache[className]
       || (cache[className] = new RegExp(
         '(?:^|\\s+)' + className + '(?:\\s+|)$'));
     ...
   }

})();

A memoizer... (*)
(That `cache[className]` boolean check should probably be guarded
against `Object.prototype` properties)

var addClassName = (function(){
var cache = {};
return function(element, className) {
var re = cache.hasOwnProperty(className) ? cache[className] :
(cache[className] = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|)
$'));

...
}
})();

(*) "JavaScript: The Good Parts", by Douglas Crockford, page 44.
 
T

Thomas 'PointedEars' Lahn

kangax said:
How are they more reliable than, say:

new RegExp("(^|\\s+)" + sClassName + "(\\s+|$)");

The only difference I see is that regex from your version will not enter
second alteration in - (^\s*|\s+) - when matched against a string that
starts with 1+ spaces (since ^\s* will succeed before).

You mean the second alternative of the first _alternation_.

This is why I thought you made it like so for performance reasons.

That was not my intention. As I said, I copied the call from
removeClassName(). But I might test efficiency later.
Which changes in ES5 are you talking about?

I confused the issues. In the ES 5 Final Draft, it says that RegExp
initializers, regardless of structure, represent a different RegExp object
each, while in ES 3 all RegExp initializers that are the same refer to the
same RegExp object. *That* is not an issue here as no initializers are used.
And which cost is involved looking up the RegExp?

Just to clarify what I meant:

var addClassName = (function(){
var cache = {};
return function(element, className) {
var re = cache[className]
|| (cache[className] = new RegExp(
'(?:^|\\s+)' + className + '(?:\\s+|)$'));
...
}
})();

However, caching RegExp objects like this carries with it the possibility
that the matcher will not start at the beginning of input but at the last
matched position. And:
(That `cache[className]` boolean check should probably be guarded
against `Object.prototype` properties)

It needs to be guarded against much more than that, cf. my Map()
implementation. And those precautions are what makes the lookup probably
more expensive than what the avoided RegExp() call is worth.


PointedEars
 
J

Jorge

(...)
Yes, indeed. Even `hasOwnProperty` is not reliable and is missing in
some of the older clients.

I get the "is missing in some of the older clients" part..., but not
the "it isn't reliable". Why not ?

TIA,
 
J

Jorge

Jorge wrote:
(...)
I get the "is missing in some of the older clients" part..., but not
the "it isn't reliable". Why not ?

"__proto__" is a good example. Not only property with that name exists
*directly* on all objects (in clients based on, say, Gecko and WebKit),
but assignment to it also modifies object's [[Prototype]].

Hmmm, does this make .hasOwnProperty() unreliable ?
I would "work around" it by prepending a random string of a sufficiently
large length. For a more robust solution, one would probably need a
safer solution, such as PointedEars' Map (recently discussed here).

ISTM that it's just a matter (to be 100% safe) of putting the "key" at
the RHS of the assignment... i.e. saved as data, not as a property.
I've not seen neither know what that Lahn's "map" thing is. Can wait
for ES5 and Object.create with a null prototype :)
 
T

Timo Reitz

kangax said:
Sure. Storing it in array would eliminate those "annoyances". But then
you go from O(1) to O(N), don't you?

Or use a self-balancing binary search tree, then it would be O(log n).
 
D

Dr J R Stockton

In comp.lang.javascript message <XvCdnZxA39Vss7DXnZ2dnUVZ_ridnZ2d@gigane
I would "work around" it by prepending a random string of a
sufficiently large length.

Which you do not exactly do :
uid = (Math.random() + '').slice(2);

It is possible for Math.random() to give 0.0 or 0.5 in which case the
uid is one character long. However, the uid is drawn at random from a
sufficiently large set, which is what matters.

But be aware that (when last I tested) that some browsers give fewer
different possible randoms than others :
<URL:http://www.merlyn.demon.co.uk/js-randm.htm> refers. An IE random
apparently contains 53 bits of randomness; a Chrome one only 30 bits.
 
G

Gabriel Gilini

Perhaps, we could increase (and ensure) string length by converting a
random number to its binary representation?

I prepend the timestamp to the key and it have been working fine for
me.

function Hash(){
var _hash = {};
var pre = (new Date()).getTime() + '__';

function put(key, value){
_hash[pre + key] = value;
return value;
}
//...
}
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
kangax said:
And which cost is involved looking up the RegExp?

Just to clarify what I meant:

var addClassName = (function(){
var cache = {};
return function(element, className) {
var re = cache[className]
|| (cache[className] = new RegExp(
'(?:^|\\s+)' + className + '(?:\\s+|)$'));
...
}
})();
However, caching RegExp objects like this carries with it the possibility
that the matcher will not start at the beginning of input but at the last
matched position. And:

But that shouldn't be an issue, since regex is not global here. Or am I
wrong?

No, it is only an issue in removeClassName(). An issue that might be solved
with assigning 0 to .lastIndex, provided the implementation would support
that, would there not be the cost of reliable mapping.
(That `cache[className]` boolean check should probably be guarded
against `Object.prototype` properties)
It needs to be guarded against much more than that, cf. my Map()
implementation. And those precautions are what makes the lookup probably
more expensive than what the avoided RegExp() call is worth.

Yes, indeed. Even `hasOwnProperty` is not reliable and is missing in
some of the older clients.

How it is not reliable? And yes, according to my research it is not
supported before JavaScript 1.5 (Netscape 6.0, Mozilla 1.0), JScript 5.5
(IE/MSHTML 5.5), KJS 3.2 (Konqueror 3.2) and Opera 5.02 (does anyone
know if there are names for Opera's ECMAScript implementation?).


PointedEars
 
D

Dr J R Stockton

In comp.lang.javascript message <g9idnW-aLe4TBbDXnZ2dnUVZ_qydnZ2d@gigane
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So your code are OK, albeit not as claimed above.
Thank you. I wasn't aware of this.

While the ">>" paragraph above remains true, it is only so because of
the "apparently". Recent information, notified here earlier today, id
that an IE random has fewer possible values than 53 bits suggest.
Indeed, looking at specs, I see that `Math.random` is specified to
return implementation-dependent representation of 0-1 distribution.

0.0 <= X < 1 .
Perhaps, we could increase (and ensure) string length by converting a
random number to its binary representation?

Math.round((Math.random()*1e10)).toString(2);

// "10010110100101010001000000101"

Math.random is permitted to return, as close as an IEEE Double can,
1E-10 which will give the string "1". Math.round with Math.random
usually gives an imperfect distribution; Math.floor is better.


Consider String(1e15*(Math.random()+1)).substring(1,16)

Or would one need to employ some way of manual construction?

function getUid(len) {
for (var a=[], i=len; i--; ) {
a = Math.round(Math.random());
}
return a.join('');
}

getUid(32); // "11000011000010011110110011001111"


Or

J = 30 ; S = "" ; while (J--) S += (Math.random()*36|0).toString(36)

// can give h3hclnm02qlhvbvk83eesy9sk2ilfz
// but does NOT have 36^30 possible values.

The benefit of using a[] will be insignificant for such lengths.

But your original method works; it just needs a corrected description.
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
kangax said:
Thomas 'PointedEars' Lahn wrote:
kangax wrote:
(That `cache[className]` boolean check should probably be guarded
against `Object.prototype` properties)
It needs to be guarded against much more than that, cf. my Map()
implementation. And those precautions are what makes the lookup probably
more expensive than what the avoided RegExp() call is worth.
Yes, indeed. Even `hasOwnProperty` is not reliable and is missing in
some of the older clients.
How it is not reliable? And yes, according to my research it is not

As I already said to Jorge, I was talking about implementation-specific
extensions such as "__proto__" in Gecko/WebKit.

You have not answered my question. How is .hasOwnProperty() not reliable?

My, I read that article twice and still overlooked it ...

ACK, thanks.


PointedEars
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
kangax said:
Thomas 'PointedEars' Lahn wrote:
kangax wrote:
Thomas 'PointedEars' Lahn wrote:
kangax wrote:
(That `cache[className]` boolean check should probably be guarded
against `Object.prototype` properties)
It needs to be guarded against much more than that, cf. my Map()
implementation. And those precautions are what makes the lookup probably
more expensive than what the avoided RegExp() call is worth.
Yes, indeed. Even `hasOwnProperty` is not reliable and is missing in
some of the older clients.
How it is not reliable? And yes, according to my research it is not
As I already said to Jorge, I was talking about implementation-specific
extensions such as "__proto__" in Gecko/WebKit.
You have not answered my question. How is .hasOwnProperty() not reliable?

It's not unreliable by itself (at least, I'm not aware of any clients
where it's not spec-compliant). It is implementation extensions that
make `hasOwnProperty` unreliable - e.g. you expect newly created Object
object to return `false` for a property not matching any of
`Object.prototype.*` ones (such as "__proto__"),

No, I for one certainly do _not_ expect that to happen.
but get `true` instead.

Works as designed.
Augmenting property name lowers the chance of collisions.

True, however it would appear you have not yet understood what
..hasOwnProperty() is supposed to do. Cf. ES3F, 15.2.4.5.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top