HTML+CSS+JS perfectly compatible with the TABLE fixed columns of major browsers

  • 2020-06-01 08:20:55
  • OfStack

In the enterprise application of BS architecture, when the number of columns in a table is large, a common requirement of users is to fix the first few important columns. In this way, fixed columns will be convenient for users to view data when dragging the scroll bar. The user experience is very good. Some of the heavyweight JS component libraries have this functionality as well, so is there an easier way to do it?

Common solution is to use the demand form splicing method, the solution if you want to make static web pages, or function of a simple dynamic pages, logic is simple, the technology is not complicated, it is easy to implement, but if you want to make components, more dynamic capabilities, you need to write a lot of redundant code, difficult to maintain, or even a simple function, all need to write a lot of code, such as event handling, etc., this method is relatively cumbersome, flexibility is very poor, is not a good solution.

After a long period of analysis and research, we found a very good compatibility solution through various scenarios. Generally speaking, we adopted the method of positioning calculation. Please post the code below and then make an interpretation.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> Headless document </title>
<script type="text/javascript">
function divScroll(scrollDiv){
  var scrollLeft = scrollDiv.scrollLeft;
  document.getElementById("tableDiv_title").scrollLeft = scrollLeft;
  document.getElementById("tableDiv_body").scrollLeft = scrollLeft;    
}
function divYScroll(scrollYDiv){
  var scrollTop = scrollYDiv.scrollTop;
  document.getElementById("tableDiv_y").scrollTop = scrollTop;  
}
function onwheel(event){
  var evt = event||window.event;
  var bodyDivY = document.getElementById("tableDiv_y");
  var scrollDivY = document.getElementById("scrollDiv_y");
  if (bodyDivY.scrollHeight>bodyDivY.offsetHeight){
    if (evt.deltaY){
      bodyDivY.scrollTop = bodyDivY.scrollTop + evt.deltaY*7;
      scrollDivY.scrollTop = scrollDivY.scrollTop + evt.deltaY*7;
    }else{
      bodyDivY.scrollTop = bodyDivY.scrollTop - evt.wheelDelta/5;
      scrollDivY.scrollTop = scrollDivY.scrollTop - evt.wheelDelta/5;
    }
  }
}
</script>
<style type="text/css">
body {
margin:0;
padding:0;
}
table {
border-collapse:collapse;
border:0;
border:none;
}
 
table td {
border:1px solid #000;
overflow:hidden;
padding:0 2px;
}
</style>
</head>
<body>
<div style="width:500px; position:relative; padding-right:18px;">
  <div style="position:relative;height:368px;overflow:hidden;width:100%">
  <div style="padding-left:108px; width:auto; overflow:hidden; background:#f00;" id="tableDiv_title" >
  <table border="0" cellspacing="0" cellpadding="0" >
   <tr>
    <td style="min-width:30px; max-width:30px; left:0; top:0; width:30px; overflow:hidden; background-color:#f00;position:absolute;z-index:1;">000</td>
    <td style="min-width:74px; max-width:74px; left:30px; top:0; width:74px; overflow:hidden; background-color:#f00;position:absolute;z-index:1;"> Automatic form </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
    <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
   </tr>
   </table>
   </div> 
  <div style="overflow:hidden; position:absolute;height:128px; width:100%;" id="tableDiv_y" onmousewheel="onwheel(event);" onwheel="onwheel(event);">
    <div style="padding-left:108px; width:auto;overflow:hidden;" id="tableDiv_body">
    <table border="0" cellspacing="0" cellpadding="0" >
     <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">001</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff; position:absolute; z-index:1;">002</td>
      <td style="min-width:74px; max-width:74px; left:30px; width:74px; overflow:hidden;background-color:#fff; position:absolute; z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
     <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">003</td>
      <td style="min-width:74px; max-width:74px;left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
     <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">004</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">005</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">006</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>   
     <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">007</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">008</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">009</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>
      <tr>
      <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">010</td>
      <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;"> Automatic form </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454 automatic </td>
      <td style="min-width: 100px; max-width: 100px; width: 100px;" > The last 1 column </td>
     </tr>      
    </table>
  </div>     
  </div> 
   <div style="background-color:#eee;overflow:hidden;top:150px; width:100%; z-index:2;position:absolute;">
    <div style="margin-left:108px; width:auto;overflow-x:scroll;overflow-y:hidden;" onscroll='divScroll(this);'>
      <div style="width:630px; height:1px;"></div>
    </div>
  </div>
  </div>
    <div id="scrollDiv_y" style="display:block; overflow-x:hidden; overflow-y:scroll; position:absolute; top:22px; right:0px; height:118px; padding-bottom:10px;" onscroll='divYScroll(this);'>
      <div style="width:1px; height:194px;"></div>
     </div>
  </div>
  </div>
</body>
</html>


1. Overall structure:

Page is the basic element for DIV + TABLE, fixed fixed columns using absolute positioning way, each 1 column to specify a fixed width, in order to solve the problem of bearing the scroll bar, header and body outside of the package two layer DIV respectively, the scroll bar with the method of virtual, fixed in a fixed position by JS mimic the effects of normal DIV scroll bar control.

2. Location:

The fixed column should be absolutely positioned, and the left displacement is controlled by the left attribute. In order to ensure that the fixed column floats above, set z-index as 1. In order to ensure the normal display when there is a vertical scroll bar, the outer layer DIV of the table body is absolutely positioned, which leads to the absolute positioning of the scroll bar. Also, DIV controls the left margin through the margin-left property for the header and body, as well as the inner layer of the scroll bar, leaving the offset of the fixed column free.

2. Width calculation:

The width of each 1 column to specify a fixed value, and pay attention to a key point, is to add min width and max width properties, these two properties and width values are equal, the header table body inner DIV, width is auto, adaptive table width, outer DIV width is 100%, the outermost DIV through padding - right attributes control the right padding, to the position of the vertical scroll bar free.

3. Height calculation:

Because of absolute positioning, the height of the entire table component is specified, which can be calculated, as well as the top value of the vertical scroll bar.

4. Scroll bar:

One prominent feature of this scheme is the virtual scroll bar, which simulates the horizontal scroll bar and vertical scroll bar of DIV of table body through an DIV with the width and height of 1 pixel as shown in table 1. Are using this form, one is a horizontal scroll bar so that the more beautiful, vertical scroll bar after this treatment, header and body outer DIV width need not calculate, is 100%, otherwise there is a scroll bar, the header and the horizontal scroll bar to empty out the displacement of the width of the vertical scroll bar, otherwise unable to align, this calculation is less complicated, but in some cases, there is a problem, in this not opened.

5. Rolling events:

Because the scroll bars of the table are hidden, the mouse wheel does not work, so you need to use JS to handle the mouse wheel event. The sample code in this article is compatible with common browsers. The key point here is to write onmousewheel and onwheel events at the same time. onmousewheel is compatible with IE. When calculating the rolling distance, please pay attention to the difference between deltaY and wheelDelta properties.

6. Analysis of advantages and disadvantages:

The solution in this article has been simplified, with the emphasis on making the principle clear and, in our practice, very complex. This design takes a lot of compatibility into account, including browser compatibility and various scenarios, and if the requirements are simple, there is room for simplification.

The advantage of this scheme is that if you want to make components, HTML is simple in structure, and the header and body of the table are 1 TABLE, JS control code is very clean and easy to maintain. The disadvantage is that you overcalculate. We thought this was a good solution for developing components, but static pages were a bit of a storm in a teal.

That's all for this article, I hope you enjoy it.


Related articles: