Techies' Corner. Notes
      It's kind of fun to do the impossible…
            If force doesn't work, you're not using enough…
    ASP.Net: How to fix a Scrollable Gridview With a Fixed Header using CSS

The most elegant way to avoid Gridview column headers from scrolling is well known on the Internet: define CSS class, for instance:

.GridViewHeaderHolder
{
   position:relative;
   top:expression(this.offsetParent.scrollTop-2);
   z-index:10;
}
Put your Gridview inside a "scrollable" element (<div> or <panel>) with fixed height & active scroll bars and define Gridview's header style:
<HeaderStyle CssClass="GridViewHeaderHolder" />
In most, not complicated cases this will work "out of the box" but if you have a lot of other positioning elements on the page it might behave quite "funny". The problem for a browser is to determine the "parent" whose offset it's looking for: the browser moves up the DOM until it encounters one of the elements that gives an offsetParent: <body>; an element with a position other than static; a <table>, <th> or <td>, but only if element's position is static.

We resolved the problem by using the <panel> element with style="position:relative" operand.

P.S.  Another approach is "to be more specific" and use Gridview's ID:

.GridViewHeaderHolder
{
   position:relative;
   top:expression(document.getElementById("GridviewID").scrollTop-2);
   z-index:10;
}

Good Luck!