固定表头和可滚动内容体

14

我在表格中有15列数据。我想要横向和纵向滚动,当我垂直滚动时,标题应该固定。我尝试了各种例子,但都没有成功。所有我看到的标题列都无法与数据对齐,因为列宽度根据用户选择的列数而变化。

请指导我找到正确的例子。


你能发一下你已经尝试过的代码吗? - Pais
@Pais 我同意你关于提交一些代码或视觉演示来满足所需结果的想法。 - SaidbakR
https://github.com/karaxuna/fixed-table-header - karaxuna
6个回答

11

这可以通过 CSS 轻松实现。关键是要遵循以下原则:

table {
    overflow-x:scroll;
}

tbody {
    max-height: /*your desired max height*/
    overflow-y:scroll;
    display:block;
}

更新至IE9 JSFiddle示例


@MoazzamKhan 是的。已经在生产环境中成功使用了几次。 - Anton Matyulkov
@MoazzamKhan 哈哈,我忘记添加那个我花了三个小时才找到的东西来使滚动条工作了!:D - Anton Matyulkov
如果它有效,它也会解决我的问题,你有任何可运行的代码吗? - Moazzam Khan
你有尝试使用多于一个列吗? - Moazzam Khan
4
滚动条会破坏表头列和表格主体列的对齐。 - Tim S
显示剩余4条评论

11

您可以通过一些视觉技巧来实现这一点,使用两个

标签。

<div class="Headers">
  <table class="NewHeader">
    <tr>
    </tr>
  </table>
</div>
<div class="Table">
  <table class="MyTable">
    <tr>
      <th>
      </th>
      ...
    </tr>
    <tr>
      <td>
      </td>
      ...
    </tr>
</div>

现在通过一些 JavaScript 或 JQuery,您可以获取 th 元素,将其宽度设置为与单元格宽度相匹配,并将 th 单元格移动到“表头”中

$(document).ready(function(){
    var counter = 0;
    $(".MyTable th").each(function(){
        var width = $('.MyTable tr:last td:eq(' + counter + ')').width();
        $(".NewHeader tr").append(this);
        this.width = width;
        counter++;
    });
});

现在只剩下需要给"Table" div添加overflow样式,这样如果你滚动第二个表格时,表头将保持不动。我使用jQuery来简化可读性,但同样可以用JavaScript实现。

Live Demo

示例:自动垂直滚动表体和表头


2
我创建了一个纯CSS的解决方案来解决这个问题,可能比已接受的答案更适合一些人(我似乎无法让它正常工作)。与我见过的大多数不需要固定宽度的滚动表格不同,我的表格具有由其内容确定的最小宽度。如果可能,它会换行以避免溢出其容器(除了标题,不幸的是它们不允许软换行),但一旦使用完换行机会,它就不会变窄。这迫使父元素(通常是body标签)处理水平滚动,从而保持标题和列同步。

这里是一个fiddle

这是代码:

HTML

<div class="scrollingtable">
  <div>
    <div>
      <table>
        <caption>Top Caption</caption>
        <thead>
          <tr>
            <th><div label="Column 1"/></th>
            <th><div label="Column 2"/></th>
            <th><div label="Column 3"/></th>
            <th>
              <!--more versatile way of doing column label; requires 2 identical copies of label-->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"/> <!--ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW-->
          </tr>
        </thead>
        <tbody>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
        </tbody>
      </table>
    </div>
    Faux bottom caption
  </div>
</div>

CSS

<!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->
<style>
/*the following html and body rule sets are required only if using a % width or height*/
/*html {
  width: 100%;
  height: 100%;
}*/
body {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0 20px 0 20px;
  text-align: center;
}
.scrollingtable {
  box-sizing: border-box;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  width: auto; /*if you want a fixed width, set it here, else set to auto*/
  min-width: 0/*100%*/; /*if you want a % width, set it here, else set to 0*/
  height: 188px/*100%*/; /*set table height here; can be fixed value or %*/
  min-height: 0/*104px*/; /*if using % height, make this large enough to fit scrollbar arrows + caption + thead*/
  font-family: Verdana, Tahoma, sans-serif;
  font-size: 16px;
  line-height: 20px;
  padding: 20px 0 20px 0; /*need enough padding to make room for caption*/
  text-align: left;
}
.scrollingtable * {box-sizing: border-box;}
.scrollingtable > div {
  position: relative;
  border-top: 1px solid black;
  height: 100%;
  padding-top: 20px; /*this determines column header height*/
}
.scrollingtable > div:before {
  top: 0;
  background: cornflowerblue; /*header row background color*/
}
.scrollingtable > div:before,
.scrollingtable > div > div:after {
  content: "";
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  left: 0;
}
.scrollingtable > div > div {
  min-height: 0/*43px*/; /*if using % height, make this large enough to fit scrollbar arrows*/
  max-height: 100%;
  overflow: scroll/*auto*/; /*set to auto if using fixed or % width; else scroll*/
  overflow-x: hidden;
  border: 1px solid black; /*border around table body*/
}
.scrollingtable > div > div:after {background: white;} /*match page background color*/
.scrollingtable > div > div > table {
  width: 100%;
  border-spacing: 0;
  margin-top: -20px; /*inverse of column header height*/
  margin-right: 17px; /*uncomment if using % width*/
}
.scrollingtable > div > div > table > caption {
  position: absolute;
  top: -20px; /*inverse of caption height*/
  margin-top: -1px; /*inverse of border-width*/
  width: 100%;
  font-weight: bold;
  text-align: center;
}
.scrollingtable > div > div > table > * > tr > * {padding: 0;}
.scrollingtable > div > div > table > thead {
  vertical-align: bottom;
  white-space: nowrap;
  text-align: center;
}
.scrollingtable > div > div > table > thead > tr > * > div {
  display: inline-block;
  padding: 0 6px 0 6px; /*header cell padding*/
}
.scrollingtable > div > div > table > thead > tr > :first-child:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 20px; /*match column header height*/
  border-left: 1px solid black; /*leftmost header border*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
.scrollingtable > div > div > table > thead > tr > * + :before {
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  color: white; /*header row font color*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
.scrollingtable > div > div > table > thead > tr > * + :before {
  content: "";
  display: block;
  min-height: 20px; /*match column header height*/
  padding-top: 1px;
  border-left: 1px solid black; /*borders between header cells*/
}
.scrollingtable .scrollbarhead {float: right;}
.scrollingtable .scrollbarhead:before {
  position: absolute;
  width: 100px;
  top: -1px; /*inverse border-width*/
  background: white; /*match page background color*/
}
.scrollingtable > div > div > table > tbody > tr:after {
  content: "";
  display: table-cell;
  position: relative;
  padding: 0;
  border-top: 1px solid black;
  top: -1px; /*inverse of border width*/
}
.scrollingtable > div > div > table > tbody {vertical-align: top;}
.scrollingtable > div > div > table > tbody > tr {background: white;}
.scrollingtable > div > div > table > tbody > tr > * {
  border-bottom: 1px solid black;
  padding: 0 6px 0 6px;
  height: 20px; /*match column header height*/
}
.scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
.scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /*alternate row color*/
.scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /*borders between body cells*/

这里有一篇文章,讲解如何创建一个带有固定表头的HTML表格,可以点击此处查看。


0
这是一个使用TableAdjuster和TableData类的纯JavaScript解决方案:

<!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>
    <title></title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style>
      .hdrDiv
      {
        width: 100%;
        overflow-x: hidden;
      }
      .tblDiv
      {
        overflow-y: auto;
        overflow-x: hidden;
        margin: 0;
        padding: 0;
        height: 500px;
      }
      .hdr
      {
        width: 100%;
      }
      .hdr td, .tbl td
      {
        padding-left: 8px;
        padding-right: 8px;
        vertical-align: middle;
        border-style: solid;
        border-width: 1px;
        border-color: rgb(163,163,163);
        text-align: left;
        cursor: default;
        margin: 0;
      }
      .hdr td
      {
        font: bold 12px Tahoma;
        padding-top: 4px;
        padding-bottom: 4px;
      }
      .hdr td.col1
      {
        width: 20%;
      }
      .hdr td.col2
      {
        width: 20%;
      }
      .hdr td.col3
      {
        width: 25%;
      }
      .hdr td.col4
      {
        width: 35%;
      }
      .hdr, .tbl
      {
        table-layout: fixed;
        min-width: 400px;
      }
      .tbl td
      {
        font: 12px Tahoma;
      }
    </style>

    <script type="text/javascript">
      var g_adjuster = null;
      var g_initRowCount = 4;

      function getScrollbarWidth()
      {
        var outer = document.createElement("div");
        outer.style.visibility = "hidden";
        outer.style.width = "100px";
        document.body.appendChild(outer);
        var widthNoScroll = outer.offsetWidth;
        outer.style.overflow = "scroll";
        var inner = document.createElement("div");
        inner.style.width = "100%";
        outer.appendChild(inner);        
        var widthWithScroll = inner.offsetWidth;
        outer.parentNode.removeChild(outer);
        return widthNoScroll - widthWithScroll;
      }
      function ExtractInt(value)
      {
        var regExp = /([a-zA-Z])/g;
        value = value.replace(regExp, "");
        return (value.length == 0) ? 0 : parseInt(value);
      }
      function TableData(hdrID, tableID)
      {
        this.m_hdrID = hdrID;
        this.m_tableID = tableID;
        this.m_pbWidth = 0;
        var header = document.getElementById(this.m_hdrID);
        var table = document.getElementById(this.m_tableID);
        this.m_hasSB = table ? (table.parentNode.scrollHeight > table.parentNode.clientHeight) : false;
        var hdrRow = (header != null && header.rows.length > 0) ? header.rows[0] : null;
        var clsName = !hdrRow ? "" : (hdrRow.className.length > 0) ? hdrRow.className : (header.className.length > 0) ? header.className + " td" : "";
        var elements = [];
        elements.push({ prop: 'padding-left', value: ''});
        elements.push({ prop: 'padding-right', value: ''});
        elements.push({ prop: 'border-width', value: ''});
        this.GetCSSValues('.' + clsName, elements);
        for (var i=0; i<elements.length; i++)
        {
          var w = ExtractInt(elements[i].value);
          if (elements[i].prop == 'border-width')
            w *= 2;
          this.m_pbWidth += w;
        }
      }
      TableData.prototype.GetCSSValues = 
        function(theClass, elements)
      {
        var classLower = theClass.toLowerCase();
        var cssRules;
        for (var i = 0; i < document.styleSheets.length; i++)
        {
          var found = true;
          try
          {
            if (document.styleSheets[i]['rules'])
              cssRules = 'rules';
            else if (document.styleSheets[i]['cssRules'])
              cssRules = 'cssRules';
            else
            {
              found = false;
            }
          }
          catch(err)
          {
            break;
          }
          if (!found)
            continue;
          for (var j = 0; j < document.styleSheets[i][cssRules].length; j++)
          {
            if (typeof document.styleSheets[i][cssRules][j].selectorText != 'string')
              continue;
            var selectorLower = document.styleSheets[i][cssRules][j].selectorText.toLowerCase();
            if (selectorLower.indexOf(classLower) >= 0)
            {
              for (var k=0; k<elements.length; k++)
              {
                var v = document.styleSheets[i][cssRules][j].style.getPropertyValue(elements[k].prop);
                if (typeof v == 'string' && v.length > 0)
                  elements[k].value = v;
              }
            }
          }
        }
      }
      TableData.prototype.Adjust = 
        function(sbWidth)
      {
        var header = document.getElementById(this.m_hdrID);
        var table = document.getElementById(this.m_tableID);
        var hdrRow = (header != null && header.rows.length > 0) ? header.rows[0] : null;
        if (!hdrRow || !table)
          return;
        var hasSB = table.parentNode.scrollHeight > table.parentNode.clientHeight;
        header.style.width = hasSB ? "calc(100% - " + sbWidth.toString() + "px)" : "100%";
        var colCount = hdrRow.cells.length;
        for (var i=0; i<table.rows.length; i++)
        {
          var r = table.rows[i];
          for (var j=0; j<r.cells.length; j++)
          {
            if (j >= colCount)
              break;
            var w = hdrRow.cells[j].offsetWidth - this.m_pbWidth;
            r.cells[j].style.width = w + 'px';
          }
        }
      }
      function TableAdjuster()
      {
        this.m_sbWidth = getScrollbarWidth();
        this.m_data = [];
      }
      TableAdjuster.prototype.AddTable = 
        function(hdrID, tableID)
      {
        // We can have multiple scrollable tables on the page
        this.m_data.push(new TableData(hdrID, tableID));
      }
      TableAdjuster.prototype.Adjust = 
        function()
      {
        for (var i=0; i<this.m_data.length; i++)
          this.m_data[i].Adjust(this.m_sbWidth);
      }
      function DeleteRow()
      {
        var table = document.getElementById("tablebody");
        if (table != null && table.rows.length > 0)
          table.deleteRow(table.rows.length-1);
        AdjustSize();
      }
      function AddRow(adjust)
      {
        var header = document.getElementById("header");
        var table = document.getElementById("tablebody");
        var hdrRow = (header != null && header.rows.length > 0) ? header.rows[0] : null;
        if (!hdrRow || !table)
          return;
        var colCount = hdrRow.cells.length;
        var rowNum = table.rows.length + 1;
        var r = table.insertRow(-1);
        for (var i=0; i<colCount; i++)
        {
          var c = r.insertCell(-1);
          c.innerHTML = "Row " + rowNum.toString() + " Column " + (i + 1).toString() + " content";
        }
        if (adjust)
          AdjustSize();
      }
      function AdjustSize()
      {
        g_adjuster.Adjust();
      }
      function InitPage()
      {
        for (var i=0; i<g_initRowCount; i++)
          AddRow(false);
        g_adjuster = new TableAdjuster();
        g_adjuster.AddTable("header", "tablebody");
        AdjustSize();
      }
    </script>
  </head>
  <body onload="InitPage()" onresize="AdjustSize()">
    <div id="headerDiv" class="hdrDiv">
      <table id="header" class="hdr">
        <tr>
          <td class="col1">Column 1 Title</td>
          <td class="col2">Column 2 Title</td>
          <td class="col3">Column 3 Title</td>
          <td class="col4">Column 4 Title</td>
        </tr>
      </table>
    </div>
    <div id="tableDiv" class="tblDiv">
      <table id="tablebody" class="tbl">
      </table>
    </div>
    <div style="margin-top: 12px">
      <input id="Button1" type="button" value="Add Row" onclick="AddRow(true);"/>
      <input id="Button2" type="button" value="Delete Row" onclick="DeleteRow();"/>
    </div>
  </body>
</html>


0

你应该使用一些第三方表格,比如YUI表格


-1

我找到了一个系统,它:

  • 兼容Internet Explorer 9+、Chrome、Firefox(Windows)和Safari(Mac)
  • 不使用JavaScript
  • 只使用一个div和一个table
  • 固定的页眉和页脚(除IE外),可滚动的正文。页眉和正文具有相同的列宽度

结果:enter image description here

HTML:

  <thead>
    <tr>
      <th class="nombre"><%= f.label :cost_center %></th>
      <th class="cabecera cc">Personal</th>
      <th class="cabecera cc">Dpto</th>
    </tr>
  </thead>
  <tbody>
    <% @cost_centers.each do |cc| %>
    <tr>
      <td class="nombre"><%= cc.nombre_corto %></td>
      <td class="cc"><%= cc.cacentrocoste %></td>
      <td class="cc"><%= cc.cacentrocoste_dpto %></td>
    </tr>
    <% end %>
  </tbody>
  <tfoot>
    <tr>
      <td colspan="3"><a href="#">Mostrar mas usuarios</a></td>
    </tr>
  </tfoot>
</table>

CSS:

div.cost_center{
  font-size:75%;
  margin-left:5px;
  margin-top:5px;
  margin-bottom: 2px;
  float: right;
  display: inline-block;
  overflow-y: auto;
  overflow-x: hidden;
  max-height:300px;  
}

div.cost_center label { 
  float:none;
  font-size:14px;
}

div.cost_center table{
  width:300px;
  border-collapse: collapse; 
  float:right;
  table-layout:fixed;
}

div.cost_center table tr{
  height:16px;
}
div.cost_center th{
  font-weight:normal;
}

div.cost_center table tbody{
  display: block;
  overflow: auto;
  max-height:240px;
}

div.cost_center table thead{
  display:block;
}

div.cost_center table tfoot{
  display:block;
}
div.cost_center table tfoot td{
  width:280px;
}
div.cost_center .cc{
  width:60px;
  text-align: center; 
  border: 1px solid #999;
}

div.cost_center .nombre{
  width:150px;
}
div.cost_center tbody .nombre{
  border: 1px solid #999;
}

div.cost_center table tfoot td{
 text-align:center;  
 border: 1px solid #999; 
} 

div.cost_center table th, 
div.cost_center table td { 
  padding: 2px;
  vertical-align: middle; 
}

div.cost_center table tbody td {
  white-space: normal;
  font:  .8em/1.4em Verdana, sans-serif;
  color: #000;
  background-color: white;
}
div.cost_center table th.cabecera { 
  font:  0.8em/1.4em Verdana, sans-serif;
  color: #000;
  background-color: #FFEAB5;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接