James Brandon
James Brandon

Reputation: 1400

Making the first column in a table fixed when scrolling horizontally

Is it possible to make the first column fixed when you scroll horizontally?

The other columns would be scrolled, but the 1st column should remain visible.

JSFiddle is here: http://jsfiddle.net/FSv9Y/

HTML (dummy data for testing this)

<div class="vScroll">
 <table style="width: 90%">
   <thead>
    <tr>
     <th>A1 Component</th>
     <th>A2 Component</th>
     <th>A3 Component</th>
     <th>A4 Component</th>
     <th>A5 Component</th>
     <th>A6 Component</th>
     <th>A7 Component</th>
    </tr>
   </thead>
   <tbody>
    <tr>
     <td>Line Item 1</td>
     <td>Line Item 2</td>
     <td>Line Item 3</td>
     <td>Line Item 4</td>
     <td>Line Item 5</td>
     <td>Line Item 6</td>
     <td>Line Item 7</td>
    </tr>
    <tr>
     <td>Line Item 1</td>
     <td>Line Item 2</td>
     <td>Line Item 3</td>
     <td>Line Item 4</td>
     <td>Line Item 5</td>
     <td>Line Item 6</td>
     <td>Line Item 7</td>
    </tr>
    <tr>
     <td>Line Item 1</td>
     <td>Line Item 2</td>
     <td>Line Item 3</td>
     <td>Line Item 4</td>
     <td>Line Item 5</td>
     <td>Line Item 6</td>
     <td>Line Item 7</td>
    </tr>
    <tr>
     <td>Line Item 1</td>
     <td>Line Item 2</td>
     <td>Line Item 3</td>
     <td>Line Item 4</td>
     <td>Line Item 5</td>
     <td>Line Item 6</td>
     <td>Line Item 7</td>
    </tr>
   </tbody>
  </table>
</div>

CSS (used for just the basic styling and scrolling on this demo)

/* Standardize Table Styling Across Browsers for Both Standard and Scrollable Tables */
table {border:none;border-collapse:collapse;line-height:18px;margin-right:1px;table-layout:fixed;}
th, td {margin:0px;padding:0px;}

/* Little Bit of Custom Styling for Flare */
th {background-color:#E9E9E9;border:solid 1px silver;}
td {border:solid 1px silver;}

/* Enable Scroll Styling Effect */
.vScroll {display:run-in;overflow-x:none;overflow-y:scroll;}

/* Fix Positioning Issue in IE 8 (and Earlier) and Mozilla */
.vScroll {border-left:solid 1px silver;}
.vScroll td:first-child {border-left:none;}
.vScroll thead, .vScroll tfoot {margin-left:-1px;}

/* Standardize Scrollbar in Safari to Be Same Width as Chrome, IE and Mozilla. */
::-webkit-scrollbar {width:16px;}
::-webkit-scrollbar-track {border-radius:10px;-webkit-box-shadow: inset 0 0 3px rgba(0,0,0,0.3);}
::-webkit-scrollbar-thumb {background-color:silver;border-radius:10px;-webkit-box-shadow: inset 0 0 3px rgba{0,0,0,0.5);}

JS

function ReSizeScrollTables () {
$(".vScroll").each(function (i,c) {
var ScrollBarWidth = 16; //IE, Chrome, Mozilla & Opera use Size 16 by default
var $Scroll = $(c);
var $Table = $Scroll.find("table");
var $Head = $Scroll.find("thead");
var $Foot = $Scroll.find("tfoot");
var $Body = $Scroll.find("tbody");

//Remove Cell Width Formatting
$Body.first("tr").find("th, td").each(function (i, c) { $(c).css("width", "auto"); });
$Head.find("th, td").each(function (i, c) { $(c).css("width", "auto"); });
$Foot.find("th, td").each(function (i, c) { $(c).css("width", "auto"); });

//Set Width of Table, Header, Footer and Body Elements
$Table.css("width", $Scroll.width() - ScrollBarWidth + 2);

//Disable positioning so browser can do all the hard work.
//This allows us to support min-width, max-width, nowrap, etc.
$header.css("position", "relative");
$footer.css("position", "relative");

//Navigate thru each cell hard coding the width so when the association
//is broken all of the columns will continue to align based on normal
//table rules. Only traverse the first row cells in the body for efficiency.
$body.first("tr").find("th, td").each(function (i, c) { $(c).css("width", GetWidth(c)); });
$header.find("th, td").each(function (i, c) { $(c).css("width", GetWidth(c)); });
$footer.find("th, td").each(function (i, c) { $(c).css("width", GetWidth(c)); });

//Enable positioning for fixed header positioning.
$header.css("position", "absolute");
$footer.css("position", "absolute");

$Table.css("width", $Scroll.width() - ScrollBarWidth - 3);

//Position Heading Based on Height of Heading
$Scroll.css("margin-top", ($Head.height() + 1) + "px");
$Head.css("margin-top", (($Head.height() - 1) * -1) + "px");

//Position Footer Based on Height of Scroll Host
$Scroll.css("margin-bottom", $Foot.css("height"));
$Foot.css("margin-top", $Scroll.height() - 1 + "px");
});
};

function GetWidth(c) {
var dWidth = $(c).attr(style);
return ((dWidth != null) && (dWidth.length > 0)) ? dWidth : $(c).css(style);
};

$(document).ready(function() { ReSizeScrollTables(); });
$(window).resize(function() { ReSizeScrollTables(); });

Upvotes: 0

Views: 2234

Answers (1)

VoidVolker
VoidVolker

Reputation: 1029

Some time ago I search answer for this question and found optimal solution for me: fixed div with table with first column and absolute table under it with js calculated offset and size.

CSS:

.vScroll td:first-child {
    border-left:none; 
    position: fixed; 
    background-color: white; 
} 

.vScroll th:first-child {
    border-left:none; 
    position: fixed;
}

JS:

var maxw = 0;
var maxh = 0;

$(".vScroll th").each( function(){
    maxw = Math.max(maxw, parseInt( $(this).css("width"), 10 ));
    maxh = Math.max(maxh, parseInt( $(this).css("height"), 10 ));
});

$(".vScroll th").css({
    width: maxw
    , height: maxh
});

maxh = 0;

$(".vScroll td").each( function(){
    maxw = Math.max(maxw, parseInt( $(this).css("width"), 10 ));
    maxh = Math.max(maxh, parseInt( $(this).css("height"), 10 ));
});

$(".vScroll td:first-child").css({
    width: maxw
    , height: maxh
});

Upvotes: 0

Related Questions