Link to home
Start Free TrialLog in
Avatar of maketechnologies
maketechnologies

asked on

Table headers that don't scroll, and stay the right size

I need to find a way to code up a table on a web page such that:

1. Each column has a header
2. The table data scrolls (can be big) but the headers remain visible at all times
3. The header for each column stays the same width as its column, and right on top of it, even with arbitrary data in the table
4. The width of the columns can not be known ahead of time - they change based on the data

We have a javascript solution at the moment, BUT it doesn't redraw the header fast enough to keep it from blinking and sliding all over the place, especially when there's a lot of data in the table.
Avatar of bruno
bruno
Flag of United States of America image

popular question lately...

you will find a few different ways to approach this around here...here is one:



<html>
<head>
  <title> scrollable table</title>
<style>
  body {background-color:moccasin}
  th {color:snow;background-color:darkkhaki}
  td {color:navajowhite;background-color:navy}
  .maindiv {background-color:tan}
</style>
<body>
  <div style="position:absolute;left:100;top:10">
     <table frame="border" width = 480>
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <tr>
           <th>first</th>
           <th>second</th>
           <th>third</th>
           <th>fourth</th>
           <th>fifth</th>
           <th>sixth</th>
        </tr>    
     </table>
     <div class="maindiv" STYLE="overflow-X:hidden;overflow-y:scroll;width:496;height:300;">
        <table frame="border" width=480 height=1200 >
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <col width=80>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
        <tr>
           <td height=60>Cd&</td>
           <td height=60>:^)</td>
           <td height=60>colC</td>
           <td height=60>xxxx</td>
           <td height=60>:^)</td>
           <td height=60>Cd&</td>
        </tr>
     </table>
  </div>    
  <table border=1 width=480 bgcolor="silver">
     <col width = 80>
     <col width = 80>
     <col width = 80>
     <col width = 80>
     <col width = 80>
     <col width = 80>
     <tr>
        <th></th>
        <th></th>
        <th></th>
        <th></th>
        <th></th>
        <th></th>
     </tr>    
  </table>
</div>
</body>
</html>
Avatar of maketechnologies
maketechnologies

ASKER

Thanks for the answer.
However, it doesn't quite solve the problem.
When I take that code and put a long string in one of the data cells, it makes the cell wider, and the headers no longer line up.
I'm looking for a solution that will keep the headers the same size as the data columns, given arbitrary data.

Any takers?
Take a look at this, I don't think you'll find a solution to matching header with col widths...


<head>
<title>Scroll test</title>
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<style>

#div1 {
    overflow: hidden;
    height: 250;
}

#div2 {
    overflow: hidden;
    width: 300;
}

#div3 {
    overflow: auto;
    width: 300;
    height:200;

}


</style>
<script>
    window.onload = function () {
         addScrollSynchronization(document.getElementById("div2"), document.getElementById("div3"), "horizontal");
         addScrollSynchronization(document.getElementById("div1"), document.getElementById("div3"), "vertical");
         //addScrollSynchronization(document.getElementById("div4"), document.getElementById("div1"), "both");
    };
    // This is a function that returns a function that is used
    // in the event listener
    function getOnScrollFunction(oElement) {
         return function () {
              if (oElement._scrollSyncDirection == "horizontal" || oElement._scrollSyncDirection == "both")
                   oElement.scrollLeft = event.srcElement.scrollLeft;
              if (oElement._scrollSyncDirection == "vertical" || oElement._scrollSyncDirection == "both")
                   oElement.scrollTop = event.srcElement.scrollTop;
         };
   
     }
    // This function adds scroll syncronization for the fromElement to the toElement
    // this means that the fromElement will be updated when the toElement is scrolled
    function addScrollSynchronization(fromElement, toElement, direction) {
         removeScrollSynchronization(fromElement);
         
         fromElement._syncScroll = getOnScrollFunction(fromElement);
         fromElement._scrollSyncDirection = direction;
         fromElement._syncTo = toElement;
         toElement.attachEvent("onscroll", fromElement._syncScroll);
    }
   
     // removes the scroll synchronization for an element
    function removeScrollSynchronization(fromElement) {
         if (fromElement._syncTo != null)
              fromElement._syncTo.detachEvent("onscroll", fromElement._syncScroll);
   
          fromElement._syncTo = null;;
         fromElement._syncScroll = null;
         fromElement._scrollSyncDirection = null;
    }
</script>
</head>

<body leftmargin=15px>
<table border=0 cellpadding=0 cellspacing=0><tr><td valign=top>
<div id=div1>
    <table border=0 cellpadding=8 cellspacing=0 style="border-color:white">
         <tr>
              <td height=60 bgcolor=#838C93 bgcolor=#838C93 align=right></td>
         </tr>
         <tr>
              <td nowrap height=70px bgcolor=#838C93 width=110><b>Row 1</td>
         </tr>
         <tr>
              <td nowrap height=70px bgcolor=#838C93 width=110><b>Row 2</td>
         </tr>
         <tr>
              <td nowrap height=70px bgcolor=#838C93 width=110><b>Row 3</td>
         </tr>
         <tr>
              <td nowrap bgcolor=#838C93 height=70px width=110><b>Row 4</td>
         </tr>
    </table>
</div>
</td><td valign=top>
<DIV id=div2 name=div2>
    <table border=0 cellpadding=8 cellspacing=0>
         <tr>
              <td nowrap height=60 width=110 align=center bgcolor=#838C93><font color=white face="Arial" style="font-size:12pt"><b>Col 1</td>
              <td nowrap height=60 width=110 align=center bgcolor=#838C93><font color=white face="Arial" style="font-size:12pt"><b>Col 2</td>
              <td nowrap height=60 width=110 align=center bgcolor=#838C93><font color=white face="Arial" style="font-size:12pt"><b>Col 3</td>
              <td nowrap height=60 width=110 align=center bgcolor=#838C93><font color=white face="Arial" style="font-size:12pt"><b>Col 4</td>
              <td nowrap height=60 width=20 align=center bgcolor=#838C93><font color=white face="Arial" style="font-size:12pt"></td>
         </tr>
    </table>
</div>
<div id=div3 name=div3>
    <table border=1 cellpadding=8 cellspacing=0>
         <tr>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 1 Col 1
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 1 Col 2
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 1 Col 3
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 1 Col 4
              </td>
         </tr>
         <tr>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 2 Col 1
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 2 Col 2
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 2 Col 3
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 2 Col 4
              </td>
         </tr>
         <tr>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 3 Col 1
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 3 Col 2
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 3 Col 3
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 3 Col 4
              </td>
         </tr>
         <tr>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 4 Col 1
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 4 Col 2
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 4 Col 3
              </td>
              <td nowrap class=BACK6 bgcolor=#CFD2D5 style="border-top-color:#FFFFFF; border-top-width:2px; border-top-style:solid" height=70px width=110>
              Row 4 Col 4
              </td>
         </tr>
    </table>
</div>
</td>
</tr>
</table>
</body>
</html>
You're right - that doesn't syncrhonize the header widths with the data cells.  But it is cool.  :)

It occurs to me - after the table is displayed, should it not be possible to read the widths of each data column, and set the header widths accordingly?

Or is there a reason nobody has proposed that?

Tom
>>read the widths of each data column

How would you do that?
Perhaps it's not possible to read the column widths at run time.  I'm admittedly ignorant of the API.  But it seems like something that ought to work.
ASKER CERTIFIED SOLUTION
Avatar of TheKenman
TheKenman
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That works beautifully in IE - thanks for that!

The Holy Grail would be a cross-browser solution, but as it happens we are designing for an intranet.

Cheers,
Tom
This is a great bit of code, but do you have any idea how to fix a footer to the table as well as a header ?

I need to somehow fix it outside the DIV, but ensure the columns are exactly the same width.
God bless u  buddy, code was treat