Html 固定标题和可滚动正文

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17753238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 11:21:16  来源:igfitidea点击:

Fixed header and scrollable body

javascripthtmlcss

提问by Harish

I have like 15 columns in the table. I want to scroll both horizontal and vertical and header should be fixed when I scroll vertical. I have tried various examples but no luck. All I see header columns are not aligning with data. Column width are not fixed as number of columns vary based on the user selection

我在表格中有 15 列。我想水平和垂直滚动,当我垂直滚动时应该固定标题。我尝试了各种示例,但没有运气。我看到的所有标题列都没有与数据对齐。列宽不固定,因为列数因用户选择而异

Please guide me to the correct example.

请指导我正确的例子。

采纳答案by LemonCool

what you could do is a bit of visual trick to achieve this, use two div tags

你可以做的是一些视觉技巧来实现这一点,使用两个 div 标签

<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>

now with a bit of JavaScript or JQuery you can get the th, set its width to match the cell width, and move the th cell to the "Headers" table

现在使用一些 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++;
    });
});

now only is left to do is to style the div "Table" with overflow, so now if you would scroll the second table the header will remain in place, i used jquery to simplify the readability, but can be done in JavaScript is same way

现在剩下要做的就是设置带有溢出的 div“表格”的样式,所以现在如果你滚动第二个表格,标题将保持原位,我使用 jquery 来简化可读性,但可以在 JavaScript 中以相同的方式完成

Live Demo

现场演示

Example with automatic vertical scroll body and header

带有自动垂直滚动体和标题的示例

回答by Anton Matyulkov

It's easily acheived with css. It all comes down to the following:

用css很容易实现。这一切都归结为以下几点:

table {
    overflow-x:scroll;
}

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

Updated for IE9 JSFiddle example

更新了 IE9 JSFiddle 示例

回答by DoctorDestructo

I have created a pure CSS solution to this problem that may work better for some people than the accepted answer (which I can't seem to get working at all). Unlike most of the other scrolling-body tables I've seen that don't require fixed widths, mine has a minimum width that is determined by its content. It will wrap text if possible to avoid overflowing its container (except in the headers, which don't allow soft-wrapping, unfortunately), but once the wrapping opportunities are used up, it won't get any narrower. That forces the parent element (usually the body tag) to handle the horizontal scrolling, which keeps the headers and columns in sync.

我已经为这个问题创建了一个纯 CSS 解决方案,对于某些人来说,它可能比公认的答案更好(我似乎根本无法工作)。与我见过的大多数不需要固定宽度的其他滚动体表格不同,我的有一个由其内容决定的最小宽度。如果可能,它将包装文本以避免溢出其容器(不幸的是,标题中不允许软包装),但是一旦包装机会用完,它就不会变得更窄。这会强制父元素(通常是 body 标签)处理水平滚动,从而使标题和列保持同步。

Here's a fiddle.

这是一个小提琴

Here's the code:

这是代码:

HTML

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

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*/


And here's a postwhere I answered in a little more detail.

而且这里有一个帖子,我在一个小更详细的回答。

回答by VladMX

Here is a pure javascript solution using TableAdjuster and TableData classes:

这是一个使用 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>

回答by Moazzam Khan

You should use some third party table, like YUI table

您应该使用一些第三方表,例如YUI 表

回答by Albert Català

I have found a system that is

我找到了一个系统

  • Compatible with Internet Explorer 9 + Chrome + Firefox (Windows) and Safari (Mac)
  • Without using javascript
  • Using only une div and one table
  • Fixed header and footer (EXCEPT for IE), with scrollable body. Header and body with same column widths
  • 兼容 Internet Explorer 9 + Chrome + Firefox (Windows) 和 Safari (Mac)
  • 不使用javascript
  • 仅使用 une div 和一张表
  • 固定页眉和页脚(IE 除外),带有可滚动的正文。具有相同列宽的标题和正文

Result:enter image description here

结果:在此处输入图片说明

HTML:

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:

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;
}