包含固定(冻结)列和标题的HTML表

时间:2017-02-02 14:35:16

标签: javascript html css

我一直在网上搜索制作带有固定(冻结)列和标题的表的方法。 好像我终于找到了解决方案并根据我的需要进行了修改。

原始小提琴是here

Here是我修改过的解决方案。我在Chrome(版本:55.0.2883.87 m)和Firefox(版本:51.0.1)中进行了测试。

问题是它在IE中的作用并不完全(版本:11.0.9600.18427)。在水平滚动期间,标题的冻结部分也会滚动。有人可以帮助我让它在IE中工作吗? 还有一个问题:这种方法可以安全使用吗?我的意思是如果它使用了一些未指明的行为,那么一些未来的浏览器甚至一些现代浏览器可能会以错误的方式显示我的表格,并且使用一些安全的解决方案会更好不同的表和同步滚动位置和行高。 UPD:还有一个问题:如何在移动设备上保持稳定?

以下是一些演示该方法的代码:



$(document).ready(function() {
  $('tbody').scroll(function(e) { //detect a scroll event on the tbody
  	/*
    Setting the thead left value to the negative valule of tbody.scrollLeft will make it track the movement
    of the tbody element. Setting an elements left value to that of the tbody.scrollLeft left makes it maintain 			it's relative position at the left of the table.    
    */
    $('thead').css("left", -$("tbody").scrollLeft()); //fix the thead relative to the body scrolling
    $('thead th:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first cell of the header
    $('tbody td:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first column of tdbody
  });
});

.container {
  height:200px; 
  width:400px;
  overflow: hidden;
}

table {
  position: relative;
  background-color: #aaa;
  border-collapse: collapse;
table-layout: fixed;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}


/*thead*/
thead {
  position: relative;
  display: block; /*seperates the header from the body allowing it to be positioned*/
}

thead th {
  background-color: #99a;
  min-width: 120px;
  border: 1px solid #222;
}

thead th:nth-child(1) {/*first cell in the header*/
  position: relative;
  background-color: #88b;
}


/*tbody*/
tbody {
  flex: 1;
  position: relative;
  display: block; /*seperates the tbody from the header*/
  overflow: auto;
}

tbody td {
  background-color: #bbc;
  min-width: 120px;
  border: 1px solid #222;
}

tbody tr td:nth-child(1) {  /*the first cell in each tr*/
  position: relative;
  background-color: #99a;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container">

  <table>
    <thead>
      <tr>
        <th>Name<br/>123</th>
        <th>Town</th>
        <th>County</th>
        <th>Age</th>
        <th>Profession</th>
        <th>Anual Income</th>
        <th>Matital Status</th>
        <th>Children</th>
      </tr>
       <tr>
        <th>Name</th>
        <th>Town</th>
        <th>County</th>
        <th>Age<br/>123<br/>321</th>
        <th>Profession</th>
        <th>Anual Income</th>
        <th>Matital Status</th>
        <th>Children</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>John Smith</td>
        <td>Macelsfield</td>
        <td>Cheshire<br/>123</td>
        <td>52</td>
        <td>Brewer</td>
        <td>£47,000</td>
        <td>Married</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Jenny Jones<br/>123<br/>312</td>
        <td>Threlkeld</td>
        <td>Cumbria</td>
        <td>34</td>
        <td>Shepherdess</td>
        <td>£28,000</td>
        <td>Single</td>
        <td>0</td>
      </tr>
      <tr>
        <td>Peter Frampton</td>
        <td>Avebury</td>
        <td>Wiltshire</td>
        <td>57</td>
        <td>Musician</td>
        <td>£124,000</td>
        <td>Married</td>
        <td>4</td>
      </tr>
      <tr>
        <td>Simon King</td>
        <td>Malvern</td>
        <td>Worchestershire</td>
        <td>48</td>
        <td>Naturalist</td>
        <td>£65,000</td>
        <td>Married</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Lucy Diamond</td>
        <td>St Albans</td>
        <td>Hertfordshire</td>
        <td>67</td>
        <td>Pharmasist</td>
        <td>Retired</td>
        <td>Married</td>
        <td>3</td>
      </tr>
      <tr>
        <td>Austin Stevenson</td>
        <td>Edinburgh</td>
        <td>Lothian </td>
        <td>36</td>
        <td>Vigilante</td>
        <td>£86,000</td>
        <td>Single</td>
        <td>Unknown</td>
      </tr>
      <tr>
        <td>Wilma Rubble</td>
        <td>Bedford</td>
        <td>Bedfordshire</td>
        <td>43</td>
        <td>Housewife</td>
        <td>N/A</td>
        <td>Married</td>
        <td>1</td>
      </tr>
      <tr>
        <td>Kat Dibble</td>
        <td>Manhattan</td>
        <td>New York</td>
        <td>55</td>
        <td>Policewoman</td>
        <td>$36,000</td>
        <td>Single</td>
        <td>1</td>
      </tr>
      <tr>
        <td>Henry Bolingbroke</td>
        <td>Bolingbroke</td>
        <td>Lincolnshire</td>
        <td>45</td>
        <td>Landowner</td>
        <td>Lots</td>
        <td>Married</td>
        <td>6</td>
      </tr>
      <tr>
        <td>Alan Brisingamen</td>
        <td>Alderley</td>
        <td>Cheshire</td>
        <td>352</td>
        <td>Arcanist</td>
        <td>A pile of gems</td>
        <td>Single</td>
        <td>0</td>
      </tr>
    </tbody>
  </table>
  
</div>
</body>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:8)

这非常奇特。似乎有问题的代码是这一行:

$('thead').css("left", -$("tbody").scrollLeft()); //fix the thead relative to the body scrolling

看起来IE11处理嵌套元素的相对位置(与Chrome和其他浏览器不同)。在这种情况下,您将thead定位为具有偏移的相对定位。您还将thead th(它的孩子)定位为偏移和相对定位。 Chrome似乎相对于thead定位table,然后相对于th定位thead。另一方面,IE11似乎相对于thead定位table,然后th只是继承相同的定位而不管其自身的位置。

对此的修复如下:在IE11上,处理thead的定位不同。而不是在父thead上设置定位,而是在thead th元素上设置定位。这样,您的第一列就不会被“强制”继承thead的定位(在IE中)。

$(document).ready(function() {
  var isIE11 = !!navigator.userAgent.match(/Trident.*rv\:11\./);
  var customScroller;
  if (isIE11)
    customScroller = function() {
      $('thead th').css("left", -$("tbody").scrollLeft()); //if using IE11, fix the th element 
    };
  else
    customScroller = function() {
      $('thead').css("left", -$("tbody").scrollLeft()); //if not using IE11, fix the thead element
    };

  $('tbody').scroll(function(e) { //detect a scroll event on the tbody
    /*
    Setting the thead left value to the negative valule of tbody.scrollLeft will make it track the movement
    of the tbody element. Setting an elements left value to that of the tbody.scrollLeft left makes it maintain             it's relative position at the left of the table.    
    */
    customScroller(); //fix the thead relative to the body scrolling
    $('thead th:nth-child(1)').css("left", $("tbody").scrollLeft());
//fix the first cell of the header
    $('tbody td:nth-child(1)').css("left", $("tbody").scrollLeft()); //fix the first column of tdbody
  });
});

以下是您的代码的完整示例,显示了基于浏览器的不同处理:

https://jsfiddle.net/8tx4xfhx/5/

Alsol,很高兴看到之前是否有人注意过这种行为。看来IE11处理嵌套相对定位的方式与其他浏览器不同。是否有某个规范定义了标准应该是什么?应该像IE一样继承相对定位吗?或者相对定位是否总是相对于父母?我会想到后者。但也必须考虑性能因素。

答案 1 :(得分:8)

您应该参考jquery.floatThead.js尝试下面的代码示例。

                    var $demoTable = $("div.table-responsive table");
                    $demoTable.floatThead({
                        top: 200,
                        scrollContainer: function ($table) {                                
                            return $table.closest('.table-responsive');
                        },
                        position: 'absolute'
                    });

你需要获取jquery.floatThead.js文件的引用并尝试在表上应用它。

您可以通过以下链接查看此信息。 http://mkoryak.github.io/floatThead/

答案 2 :(得分:6)

通常用于冷冻行和我总是喜欢使用仅限css的解决方案来实现最佳的浏览器兼容性。

我尝试使用仅限css的解决方案复制您的代码。

我正在使用Mac,因此无法访问IE。请确认它是否正常工作。

更新了小提琴:https://jsfiddle.net/nashcheez/bzuasLcz/81/

参考代码:

&#13;
&#13;
table {
  position: relative;
  width: 700px;
  background-color: #aaa;
  overflow: hidden;
  border-collapse: collapse;
}
/*thead*/

thead {
  position: relative;
  display: block;
  /*seperates the header from the body allowing it to be positioned*/
  width: 700px;
  overflow: visible;
}
thead th {
  background-color: #99a;
  min-width: 120px;
  height: 36px;
  min-height: 36px;
  border: 1px solid #222;
}
thead th:nth-child(1) {
  /*first cell in the header*/
  position: relative;
  display: block;
  background-color: #88b;
}
tbody tr td:nth-child(2) {
  margin-left: 124px;
  display: block;
}
/*tbody*/

tbody {
  display: block;
  width: 700px;
  height: 239px;
  overflow-y: auto;
}
tbody td {
  background-color: #bbc;
  min-width: 120px;
  border: 1px solid #222;
  height: 36px;
  min-height: 36px;
}
tbody tr td:nth-child(1) {
  /*the first cell in each tr*/
  position: absolute;
  display: inline-block;
  background-color: #99a;
}
&#13;
<body>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Town</th>
        <th>County</th>
        <th>Age</th>
        <th>Profession</th>
        <th>Anual Income</th>
        <th>Matital Status</th>
        <th>Children</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>John Smith</td>
        <td>Macelsfield</td>
        <td>Cheshire</td>
        <td>52</td>
        <td>Brewer</td>
        <td>£47,000</td>
        <td>Married</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Jenny Jones</td>
        <td>Threlkeld</td>
        <td>Cumbria</td>
        <td>34</td>
        <td>Shepherdess</td>
        <td>£28,000</td>
        <td>Single</td>
        <td>0</td>
      </tr>
      <tr>
        <td>Peter Frampton</td>
        <td>Avebury</td>
        <td>Wiltshire</td>
        <td>57</td>
        <td>Musician</td>
        <td>£124,000</td>
        <td>Married</td>
        <td>4</td>
      </tr>
      <tr>
        <td>Simon King</td>
        <td>Malvern</td>
        <td>Worchestershire</td>
        <td>48</td>
        <td>Naturalist</td>
        <td>£65,000</td>
        <td>Married</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Lucy Diamond</td>
        <td>St Albans</td>
        <td>Hertfordshire</td>
        <td>67</td>
        <td>Pharmasist</td>
        <td>Retired</td>
        <td>Married</td>
        <td>3</td>
      </tr>
      <tr>
        <td>Austin Stevenson</td>
        <td>Edinburgh</td>
        <td>Lothian</td>
        <td>36</td>
        <td>Vigilante</td>
        <td>£86,000</td>
        <td>Single</td>
        <td>Unknown</td>
      </tr>
      <tr>
        <td>Wilma Rubble</td>
        <td>Bedford</td>
        <td>Bedfordshire</td>
        <td>43</td>
        <td>Housewife</td>
        <td>N/A</td>
        <td>Married</td>
        <td>1</td>
      </tr>
      <tr>
        <td>Kat Dibble</td>
        <td>Manhattan</td>
        <td>New York</td>
        <td>55</td>
        <td>Policewoman</td>
        <td>$36,000</td>
        <td>Single</td>
        <td>1</td>
      </tr>
      <tr>
        <td>Henry Bolingbroke</td>
        <td>Bolingbroke</td>
        <td>Lincolnshire</td>
        <td>45</td>
        <td>Landowner</td>
        <td>Lots</td>
        <td>Married</td>
        <td>6</td>
      </tr>
      <tr>
        <td>Alan Brisingamen</td>
        <td>Alderley</td>
        <td>Cheshire</td>
        <td>352</td>
        <td>Arcanist</td>
        <td>A pile of gems</td>
        <td>Single</td>
        <td>0</td>
      </tr>
    </tbody>
  </table>
</body>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

问题在于,IE不允许调整行中单元格的left属性,而与行整体无关。我们可以通过使用IE中的开发人员窗口和Chrome中的开发人员窗口直接编辑DOM来看到这一点。

在Chrome中,当您向左和向右滚动时,您可以在元素查看器中看到元素本身的left属性已更改,这会覆盖所有CSS。我们可以重新加载页面并在同一屏幕中手动设置元素属性:style:'left:300px',我们将看到标题单元格向右移动300px并将鼠标悬停在剩余的标题单元格上。这是良好的行为以及使该方法有效的行为。

如果我们在IE中做同样的事情并将style: 'left:300px'添加到第th个元素,我们将看到该单元格不移动。我们对该单元格的样式属性所做的任何操作都不会导致它在表格中留下它的位置。 IE的这个“功能”导致该方法失败。无论将哪些属性应用于行中的元素,IE都坚持维护单元格顺序。

诀窍是以一种让所有浏览器都满意的方式解决这个复杂问题。有很多方法可以做到这一点,但我可能会使用两个表,并使用DIV来定位它们以使边匹配。我会添加javascript,以便如果一个tbody向上或向下滚动它会以相同的方式影响另一个tbody。如果它向右或向左滚动,第一个表没有任何反应,它保存你的冻结列标题,右表按计划在滚动方向上移动。

通过使用两个表,IE不再将您尝试冻结的标头与正在移动的标头相关联。小心的CSS将伪装你的黑客并使表格显示为一个表格。

祝你好运,编码愉快!