Thursday, December 01, 2011

Floating/Fixed Table Header in HTML Page or Inside DIV control

I’ve looked a lot for finding a solution were we can float a header of a table so that the header always appears on the top no matter how down do I scroll.
All the ‘floating table header’ solution ‘mostly’ worked were full HTML body is getting the scroll but none of them worked which can work inside scrolling div. None!
So I though I can create one. The concept was simple, get the ‘onScroll’ even of Div control and change CSS “top” property of table header to current scrolled position of Div. 
Unfortunately, there are many browser issues. Like mozilla doesn’t like when table cells change their position. Chrome rendering issues shows two headers rows when scrolled up.
At last, after storming through the problems, I arrived on this complex but simplified solution which is mentioned below. Copy the content in a blank HTML file and see the fun.

<html> 
    <head> 
        <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript" > </script> 
        <script  type="text/javascript"> 
            $(function() { 
                if($.browser.mozilla) 
                    //table row doean't float in firefox, div floats 
                    $(".floatingHeader" + " tr th div") 
                            .addClass("floatingStyle"); 
                else 
                    //table row can float in IE and Chrome 
                    $(".floatingHeader"+ " tr th") 
                            .addClass("floatingStyle"); 
            }); 
            function changeFloatingHeaderPosition(container, headerId) { 
                    if($.browser.webkit) //chrome rendering bug fix 
                        $("#"+headerId + " tr th") 
                            .css("visibility", "hidden"); 
                    if($.browser.mozilla) 
                        $("#"+headerId + " tr th div") 
                            .css("top", container.scrollTop); 
                    else 
                        $("#"+headerId + " tr th") 
                            .css("top", container.scrollTop); 
                    if($.browser.webkit) //chrome rendering bug fix 
                        $("#"+headerId + " tr th") 
                            .css("visibility", "visible"); 
            } 
     
      // Remove this method if you are using Jqeury earlier than 1.9
     (function() {
      var matched, browser;

      // Use of jQuery.browser is frowned upon.
      // More details: http://api.jquery.com/jQuery.browser
      // jQuery.uaMatch maintained for back-compat
      jQuery.uaMatch = function( ua ) {
   ua = ua.toLowerCase();

   var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
       /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
       /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
       /(msie) ([\w.]+)/.exec( ua ) ||
       ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
       [];

   return {
       browser: match[ 1 ] || "",
       version: match[ 2 ] || "0"
   };
      };

      matched = jQuery.uaMatch( navigator.userAgent );
      browser = {};

      if ( matched.browser ) {
   browser[ matched.browser ] = true;
   browser.version = matched.version;
      }

      // Chrome is Webkit, but Webkit is also Safari.
      if ( browser.chrome ) {
   browser.webkit = true;
      } else if ( browser.webkit ) {
   browser.safari = true;
      }

      jQuery.browser = browser;
  })();
        </script> 
        <style> 
            .floatingStyle 
            { 
                position:relative; 
                background-color:#829DC0; 
                top:0px; 
            } 
        </style> 
    </head> 
<body> 
    <div class="floatingContainer"     onscroll="changeFloatingHeaderPosition(this, 'idHeader' );"      style="height:150px; width: 100px;overflow:auto;"> 
        <table cellspacing=0 cellpadding=0> 
            <thead class="floatingHeader" id="idHeader"> 
                <tr> 
                    <th><div>Col1</div></th>                     <th ><div>Col2<div></th> 
                    <th ><div>Col3<div></th> 
                </tr> 
            </thead> 
            <tbody> 
                <tr><td>first_row</td><td>first_row</td><td>first_row</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr> 
                <tr><td>data</td><td>data</td><td>data</td></tr>             </tbody> 
        </table> 
</div></body><html>
Note: Dan/Kenji has written plugging for the same which might be useful to you. I've not verified if it works in all case but worth having a look. You can find it: here: http://www.redkitetechnologies.com/2013/03/floatingsticky-headers-for-visualforce-pageblocktable/