This did NOT work in Konqueror 3.2.3 and may not work in some version of other KHTML best browsers like Safari.
In this tutorial, the columns of a table are highlighted when the mouse cursor is over them. This is a traditional rollover effect. In this example, it is accomplished by changing the class of the cols tag.
One issue with this method has to do with the odd nature of the cols and colgroup tags. They don't have descendants! The rows and cells are not children of the cols or colsgroup even though they may take the appearance of styles applied to those tags. This is the only instance that I know of where the styles applied to an element can affect elements that are not its descendants.
You cannot use child selectors involving the cols tag and td or tr tags (or any other tags for that matter). As a consequence, any style applied to the td or tr tag overrides cols styles.
Try it! Run your mouse over the table and see the cell colors change.
Column1 | Column2 | Column3 |
---|---|---|
Data 1.1 | Data 1.2 | Data 1.3 |
Data 2.1 | Data 2.2 | Data 2.3 |
Data 3.1 | Data 3.2 | Data 3.3 |
Data 4.1 | Data 4.2 | Data 4.3 |
A combination of JavaScript and CSS is used to accomplisht the rollover effect. Here is the CSS class that is used to highlight the column.
table { margin: 0; border: 5px outset #099; border-spacing: 0; background-color: #066; color: #fff; } th { border: 1px inset #fff; padding: 4px; background-color: #00c; color: #fff; } td { border: 1px inset #fff; padding: 4px; } .hlt { background-color: #999; color: black; }
Here is what the table looks like.
<table border="5" cellpadding="4" cellspacing="2"> <col id="c1" /><col id="c2" /><col id="c3" /> <thead> <tr><th>Column1</th><th>Column2</th><th>Column3</th></tr> </thead> <tbody id="binding"> <tr><td>Data 1.1</td><td>Data 1.2</td><td>Data 1.3</td></tr> <tr><td>Data 2.1</td><td>Data 2.2</td><td>Data 2.3</td></tr> <tr><td>Data 3.1</td><td>Data 3.2</td><td>Data 3.3</td></tr> <tr><td>Data 4.1</td><td>Data 4.2</td><td>Data 4.3</td></tr> </tbody> </table>
The orignal colors for the cells are set in the table style, and a style rule for the headings prevents them changing. (Also binding the event to the tbody and only processing td elements keeps the headers from changing.)
Notice that the col tags (there is no difference if colgroup tags are used) are not ancestor nodes of the rows or cells. This—and limited support—is what makes them difficult to use.
The col tags have IDs that incorporate a sequential number so the code can access them based on the TD's cellIndex property. Let's look at the code.
<script type="text/javascript"> function getCellIndex(cell) { var rtrn = cell.cellIndex || 0; if (rtrn == 0) { do{ if (cell.nodeType == 1) rtrn++; cell = cell.previousSibling; } while (cell); rtrn--; } return rtrn; } function mouse_event (e){ var e = e || window.event; var obj = e.srcElement || e.target; var tn = (obj.nodeType == 1)?obj.tagName.toLowerCase():'x'; while(tn !="td" && tn != "tbody"){ obj= obj.parentNode || obj.parentElement; tn = obj.tagName.toLowerCase(); } if (tn == "td") { var idx = getCellIndex(obj); switch (e.type) { case 'mouseover': document.getElementById("c" + ++idx).className = "hlt"; break; case 'mouseout': document.getElementById("c" + ++idx).className = ""; break; } } } window.onload = function () { document.getElementById("binding").onmouseover = mouse_event; document.getElementById("binding").onmouseout = mouse_event; }; </script>
Techniques used here are introduced in Table Cell Rollover using Event Object and Table Row Rollover using Event Object. The event handler is bound to the tbody by assignment to that object's properties, onmouseover and onmouseout. Here are the steps performed in the event handler.
Only a cell can be processed because that is the only element that has a property, cellIndex, that specifies the column position.
In the event handler, the code makes a call to getCellIndex with the cell as an argument. That function returns the cellIndex or equivalent value. This is a zero base index for the position of the cell in the row. That value is incremented so it matches the possible col IDs ( 1 through 3) and is concatenated with the letter C to make a valid ID.
The function getCellIndex is needed because some browsers do not properly support the cellIndex property of the TD and TH elements. The function first tries to get the property value. If the value is zero—some browser return zero for all cells—then the number of cells to the left are counted. Only node type 1, an HTML element, is counted. Gecko based browser sometimes add text nodes (type 3) for new lines between tags in the html. The count is decremented to make it zero based (not what the remainder of the code needs, but cellIndex is a zero based number so doing this better matches expectations and the function is more reusable).
As can be seen, using the COL or COLGROUP elements provides a means to highlight columns and can be usefull; albeit, in a limited way.
I received an email from John Wright, living in the UK—or so I believe since he has a UK email address—sharing his enhancement to this method.
John's case required that some columns (for example, row headers) remain unchanged. while those with data change. He noted that the process was dependent on the format of the cols tag's id, and by leaving some columns without an id or giving them ids that don't fit the format those columns would not be highlighted.
Column1 | Column2 | Column3 | ||
---|---|---|---|---|
row 1 heading | Data 1.1 | Data 1.2 | Mid Heading | Data 1.3 |
row 2 heading | Data 2.1 | Data 2.2 | Mid Heading | Data 2.3 |
row 3 heading | Data 3.1 | Data 3.2 | Mid Heading | Data 3.3 |
row 4 heading | Data 4.1 | Data 4.2 | Mid Heading | Data 4.3 |
To implement this, some minor code changes were needed and are highlighted in the following code sample. The changes prevent an error when handling the columns where highighting is blocked, and simply test whether or not an element has the generated ID.
function mouse_event (e){ var e = e || window.event; var obj = e.srcElement || e.target; var tn = (obj.nodeType == 1)?obj.tagName.toLowerCase():'x'; while(tn !="td" && tn != "tbody"){ obj= obj.parentNode || obj.parentElement; tn = obj.tagName.toLowerCase(); } if (tn == "td") { var idx = getCellIndex(obj); var column = document.getElementById("x" + ++idx); if (column) { switch (e.type) { case 'mouseover': column.className = "hlt"; break; case 'mouseout': column.className = ""; break; } } } }
There are actually two ways to handle blocking the highlight on some columns.
John's method is necessary when the cells in the column are composed of td tags;
like the ones that say "mid heading."
The other way is to use th tags like the first column.
This code line, if (tn == "td")
, causes
highlighting to be applied only when the cells are td elements.
Thanks for the feedback and suggestion, John!