【问题标题】:Fixed header and scrollable body固定标题和可滚动正文
【发布时间】:2017-02-14 06:19:30
【问题描述】:

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

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

【问题讨论】:

标签: javascript html css


【解决方案1】:

你可以做的是一些视觉技巧来实现这一点, 使用两个 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>

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

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

Live Demo

Example with automatic vertical scroll body and header

【讨论】:

    【解决方案2】:

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

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

    为 IE9 更新 JSFiddle example

    【讨论】:

    • @MoazzamKhan 是的。在 prod 中成功使用了几次
    • @MoazzamKhan 哈哈,忘了添加我花了三个小时才找到的东西,才能让卷轴工作! :D
    • 如果它有效,它也能解决我的问题,你有运行代码吗?
    • 您是否尝试过使用多个列?
    • 滚动条打乱了 thead 列和 tbody 列的对齐方式。
    【解决方案3】:

    我为这个问题创建了一个纯 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*/
    

    还有here's a post,我回答得更详细一点。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          我找到了一个系统

          • 兼容 Internet Explorer 9 + Chrome + Firefox (Windows) 和 Safari (Mac)
          • 不使用javascript
          • 只使用一个 div 和一个表
          • 修复了页眉和页脚(IE 除外),正文可滚动。具有相同列宽的标题和正文

          结果:

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

          【讨论】:

            猜你喜欢
            • 2021-12-25
            • 1970-01-01
            • 2019-06-14
            • 1970-01-01
            • 1970-01-01
            • 2019-04-30
            • 2019-12-19
            相关资源
            最近更新 更多