Background color for elements inside each other

I was wondering how to split the elements inside each other, so that each of them has its own background color. What I’m trying to do is to highlight background of each element onmouseover. Up till now I haven’t managed to do it properly - for example, I have a table cell with a hyperlink inside it. When I point to the cell - background changes, however, pointing to the hyperlink leaves the cell coloured - which is what I don’t want. Look at what I’m trying to do:
http://img825.imageshack.us/img825/4371/20613904.png

I’m trying to use this code:

onMouseOver="this.style.backgroundColor='yellow';" onMouseOut="this.style.backgroundColor='white';"

Any suggestions?

This is better done with CSS.

I’m not really clear on what you do want. Could you explain more clearly what you want to hapen 1) which you hove over the cell (but not the link) and 2) what should happen when you hver over the link.

I’ve hosted an example file (example.html) to show what I’m trying to do. Hope it’ll be clear now.
http://www.2shared.com/document/w_BuGU9N/example.html

You can just post full page code like that right here, so let me do it to save other following your link:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>

<table width="100%" border="1" height="200">
	<tr>
    	<td><a href="#" onMouseOver="this.style.backgroundColor='yellow';" onMouseOut="this.style.backgroundColor='#FFFFFF';">Highlight a link on mouseover</a></td>
        <td onMouseOver="this.style.backgroundColor='yellow';" onMouseOut="this.style.backgroundColor='#FFFFFF';">Highlight a cell on mouseover</td>

		<td onMouseOver="this.style.backgroundColor='yellow';" onMouseOut="this.style.backgroundColor='#FFFFFF';"><a href="#" onMouseOver="this.style.backgroundColor='yellow';" onMouseOut="this.style.backgroundColor='#FFFFFF';">Now highlight a cell when I hover over it -> working.<br />
When I hover over link - highlight it, stop higlighting cell -> doesn't work</a></td>
    </tr>
</table>

</body>
</html>


OK, what you are trying to do here is affect a parent element on the basis of a child, which you can’t really do with CSS, so you may have to stick with JS. I’ll move this thread to the JS forum.

Thanks Ralph.

Dante, what you can do is to remove the inline HTML attributes for the events, and move them out to where they belong as scripting code.

We’ll put an id attribute on each td, just for the purposes of testing this. We should be able to get rid of most of them by the time we finish this.


<td id="first"><a href="#">Highlight a link on mouseover</a></td>
<td id="second">Highlight a cell on mouseover</td>
<td id="third"><a href="#">Now highlight a cell when I hover over it -> working.<br />...</a></td>

At the end of the body, just before the </body> tag, is where we put the script. That allows the script to easily work with elements on the page before the page is loaded.


<body>
    ...
    <script type="text/javascript" src="js/script.js"></script>
</body>

The script.js file will contain the scripting that we do.

In that script we want to gain a reference to each of the parts you’re testing there, and to set the mouseover background. Because that’s a behaviour that will be common to several elements on the page, we’ll use a single function to set up each element.


function initMouseoverBackground(el, color) {
    el.onmouseover = function () {
        this.style.backgroundColor = color;
    };
    el.onmouseout = function () {
        this.style.backgroundColor = '';
    };
}

Notice how on mouseout we’re not setting the color to white, but are clearing the backgroundColor setting? This is because javascript is creating a whole new set of CSS declarations in a style attribute on the element, so removing the backgroundColor setting from that inline style attribute allows the element to revert back to what it was before.

Now we can use that initMouseoverBackground function to set up the mouseover behaviour for each element.


var el = document.getElementById('first').getElementsByTagName('a')[0];
initMouseoverBackground(el, 'yellow');
el = document.getElementById('second');
initMouseoverBackground(el, 'yellow');
el = document.getElementById('third');
initMouseoverBackground(el, 'yellow');
var el = document.getElementById('third').getElementsByTagName('a')[0];
initMouseoverBackground(el, 'yellow');

That works on all but the third section link, because according to the way that mouseover works, it considers that you’re also over all the parent elements of that link as well, which includes the td, tr, table and body elements. When you hover over the link, the mouseover event bubbles up from the link all the way up.

You want only the link to be highlighted, so we should cancel the event from bubbling further up so that it doesn’t trigger the hover on the td itself.
We can do that by adding a parameter for the event (getting the event from window.event if we’re on Internet Explorer) and cancelling the bubbling of the event.


el.onmouseover = function (evt) {
    evt = evt || window.event;
    evt.cancelBubble = true;

    this.style.backgroundColor = color;
};

With that modification in place things now work as you seem to prefer.

I’ll follow this post with one that removes the multiple identifiers and sets up mouseover event for every element within the table.

Let’s now remove the id attributes from all of those TD elements and put one on the TR element


<tr id="first">
    <td><a href="#">Highlight a link on mouseover</a></td>
    <td>Highlight a cell on mouseover</td>
    <td><a href="#">Now highlight a cell when I hover over it -> working.<br />...</a></td>
</tr>

What we want here is to capture the hover event when it bubbles up to the TR element, and to highlight only the element that the mouse is hovering over.

Here’s how we can adjust the onmouseover event to achieve that. We get the target element from the event and highlight that element instead. That way when we hover over a link, it’s the link that gets highlighted. If we hover instead over a table cell it’s only that table cell that gets highlighted.


el.onmouseover = function (evt) {
    evt = evt || window.event;
    var targ = evt.target || evt.srcElement;
    targ.style.backgroundColor = color;
};

Nearly identical code can be used in the initMouseoverBackground function for the onmouseout event too:


el.onmouseover = function (evt) {
    evt = evt || window.event;
    var targ = evt.target || evt.srcElement;
    targ.style.backgroundColor = color;
};

The only problem now is that both functions are nearly identical, so we should extract that out to a separate function, so we can just make this call instead:


el.onmouseover = colorTargetBackground(el, 'yellow');
el.onmouseout = colorTargetBackground(el, '');

That can be done by creating a colorTargetBackgroundfunction that returns a function (for the event) that uses the passed color.


function colorTargetBackground(el, color) {
    return function (evt) {
        evt = evt || window.event;
        var targ = evt.target || evt.srcElement;
        targ.style.backgroundColor = color;
    };
}

So we’re left with only two pieces of scripting code. An initMouseoverBackground function that has the setTargetBackgroundColor function with a couple of lines after it to attach it to the onmouseover and onmouseout events, and after the initMouseoverBackground function we also have a few lines to start setting things up.

This is the full scripting code that we’re left with after performing the above changes:


function initMouseoverBackground(el, color) {
    function colorTargetBackground(el, color) {
        return function (evt) {
            evt = evt || window.event;
            var targ = evt.target || evt.srcElement;
            targ.style.backgroundColor = color;
        };
    }

    el.onmouseover = colorTargetBackground(el, 'yellow');
    el.onmouseout = colorTargetBackground(el, '');
}

var el = document.getElementById('first');
initMouseoverBackground(el, 'yellow');

Woow, what 2 great posts from you, Paul - really excellent - thanks! Perhaps then you could give some indications of what to do if I want each element on the page to have this ability to be highlighted - I understand it’s a loop, but how to target every element - I have no idea. Maybe somehow dynamically adding onmouseover, onmouseout a function to each element with ‘this’ argument and color?

Instead of having the event attached to the TR element, you can have the event attached to document.body

Thanks for the quick replying and for all the help - works perfectly!!!