水平滚动的桌子上的“粘滞”标题...完全不可能吗?

时间:2019-07-08 07:42:20

标签: javascript jquery html css html-table

在研究了最近几个小时之后,我开始认为这是不可能的,即使在最新的浏览器中也是如此:

具有水平滚动的HTML table元素,顶部是“粘性” thead,是垂直滚动的周围网页的一部分。

这是我的尝试:

#a {
  height: 100px;
  background-color: green;
}

body {
  width: 100%;
}

#wrapper {
  overflow-x: scroll;
  width: 100%;
}

th {
  position:sticky;
  top: 0;
  background-color: red;
  z-index: 1;
}

td {
  white-space: nowrap;
}

#b {
  height: 2000px;
  background-color: blue;
}
<div id="a">
  some content
</div>

<div id="wrapper">
  <table id="test">
    <thead>
      <tr>
        <th>sticky header</th>
        <th>sticky header</th>
        <th>sticky header</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
    </tbody>
  </table>
</div>
<div id="b">
  some more content
</div>

(还有this fiddle,因此您可以弄乱代码)

当前的方式是,当#wrapperoverflow-x: scroll时,“位置:粘性”不起作用。如果删除了overflow-x规则,它会起作用,但是当然表格会扩展整个页面的宽度(绝对不酷)

我知道使表格成为“ scrolling”元素可以解决此问题,但这也不可取(我只希望网页主体可以垂直滚动)。

我试图提出其他CSS解决方案,甚至Javascript解决方案,但我想不出最终可行的解决方案。这实际上是不可能的吗?

虽然我希望使用css解决方案,但现在我可以使用JavaScript解决方案。

5 个答案:

答案 0 :(得分:1)

有一个fiddle并附有有效的示例。您甚至可以通过预先声明宽度/高度来摆脱一些JavaScript。

在原始示例中添加了一些ID

<div id="a">
  some content
</div>

<div id="wrapper">
  <table id="test">
    <thead id="sticky">
      <tr id="headerRow">
        <th>sticky header</th>
        <th>sticky header</th>
        <th>sticky header</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
    </tbody>
  </table>
</div>
<div id="b">
  some more content
</div>

下面是JavaScript

// When the user scrolls the page, execute addSticky 
window.onscroll = function() {addSticky()};
document.getElementById("wrapper").onscroll = function(){addSticky()};

// Get the header
var header = document.getElementById("sticky");

// Get the offset position
var sticky = header.offsetTop;

// Get bottom offset
var bottomOffset = document.getElementById("test").offsetHeight+100;


// Set the width of the row and columns by placing them in an array and looping said array
var headerRow = document.getElementById("headerRow");
header.style.width = headerRow.offsetWidth+"px";
var headerKids = headerRow.children;
for (var i=0; i<headerKids.length; i++){
  headerKids[i].style.width=headerKids[i].offsetWidth+"px";
}

// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
function addSticky() {
  if (this.scrollY > 100 && this.scrollY < bottomOffset ) {
    xScroll = document.getElementById("wrapper").scrollLeft;
    header.classList.add("sticky");
    header.style.left = "-"+xScroll+"px";
  } else {
    header.classList.remove("sticky");
  }
}

更新为CSS

.sticky {
  position: fixed;
  top: 0;
  height: 20px;
}

答案 1 :(得分:0)

这与您要求的不完全相同,但是请尝试篡改该表:

https://codepen.io/joelPrz/pen/Gclki

for ($i = 0; $i < count($request->products); $i++) {
    $l           = $request->products[$i]['location'];
    // I change it to first instead of get
    $locations[] = DB::table('locations')->select('*')->where('location_id', $l)->first();
}
// do foreach loop to fetch that data
foreach ($locations as $key => $location) {
    echo $key . "&nbsp; -" . $location->location_id . "<br>";
}
var tee = $('.gridtable thead');
var tw = document.getElementsByClassName('tabWrap')[0];
var cloner = document.getElementsByClassName('tabWrap')[0];
var bd = document.getElementsByClassName('container')[0];
var newTableWrap = document.createElement("div");
var newTable = document.createElement("Table");
var oldTable = document.getElementsByClassName('gridtable')[0];
var childNode = oldTable.childNodes[1];
var wrapW = $(tw).css('width');
var wrapY = $(tw).css('height');
var headHeight = tee.css('height');

//node The node to be cloned.
var dupNode = childNode.cloneNode(true);
newTable.appendChild(dupNode);
newTableWrap.appendChild(newTable);

newTable.classList.add("gridtableT");
newTable.classList.add("gridtable");

$(newTableWrap).css({'width': wrapW, 'overflow':'hidden'});

bd.insertBefore(newTableWrap , tw);
$(oldTable).css('margin-top', ('-' + headHeight) );

$('tr td').filter(":last-child")
  .css('border-right-color', 'transparent');

$('tr:last td').css('border-bottom-color', 'transparent');

$(tw).on('scroll', function(e){
  var newLeft = e.target.scrollLeft;
  $(newTable).css('margin-left', '-' + newLeft + 'px');
});
table { border-collapse: collapse; }

th, td {
  border-left-color: transparent!important;
}

.last-cell {
  border-right-color: transparent!important;
}

.container {
  outline: 1px solid black;
  outline-offset: 0px;
  width: 800px;
}

.tabWrap {
  height: 500px;
  margin-right: 30px;
  margin-bottom: 0;
  overflow: scroll;
  width: 800px;
}

.gridtable {
  color:#333333;
  font-family: verdana,arial,sans-serif;
  font-size:11px;
}

.gridtable th {
  border-width: 1px;
  border-style: solid;
  border-color: #666666;
  background-color: #dedede;
  padding: 8px;
}

.gridtable td {
  border-width: 1px;
  padding: 8px;
  border-style: solid;
  border-color: #666666;
  background-color: #ffffff;
}

.gridtableT { color: red; }

.gridtableT th { border-top-color: transparent; }

.lastRow td {
  background-color: lightcyan;
}

div.tabWrap th {
  border-bottom-color: transparent!important;
  border-top-color: transparent!important;
}

页眉是粘性的,但仅在表格内部,而不在页面内部。因此maby您可以根据自己的需要进行更改。

(通过链接打开代码,我在此处复制的代码有某种错误)

答案 2 :(得分:0)

如果您使用overflow以外的其他任何方式使用visible,则必须为元素提供固定的高度,否则,当滚动父元素时,该元素已准备好粘贴,但高度不受限制。

一个简单的CSS解决方案是使用视口(即#wrapper)来赋予vh高度

#wrapper {
  height: 30vh;
  overflow-x: scroll;
  width: 100%;
}

#a {
  height: 100px;
  background-color: green;
}

body {
  width: 100%;
}

#wrapper {
  overflow-x: scroll;
  width: 100%;
  height: 30vh;
}

th {
  position:sticky;
  top: 0;
  background-color: red;
  z-index: 1;
}

td {
  white-space: nowrap;
}

#b {
  height: 2000px;
  background-color: blue;
}

#scroller{
  width: 100%;
  height: 400px;
  overflow:auto;
}
<div id="a">
  some content
</div>

<div id="wrapper">
  <table id="test">
    <thead>
      <tr>
        <th>sticky header</th>
        <th>sticky header</th>
        <th>sticky header</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
        <td>long content long content long content long content long content long content</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
    </tbody>
  </table>
</div>
<div id="b">
  some more content
</div>

答案 3 :(得分:0)

position: sticky用于表是适用的。请参见下面的代码。

thead th { position: sticky; top: 0; }
<table>
    <thead>
        <tr>
            <th>column 1</th>
            <th>column 2</th>
            <th>column 3</th>
            <th>column 4</th>            
        </tr>    
    </thead>
    <tbody>
    <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
      <tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr><tr>
        <td>Data One</td>
        <td>Data Two</td>
        <td>Data Three</td>
        <td>Data Four</td>
      </tr>
    </tbody>
</table>

请参阅https://caniuse.com/#feat=css-sticky,在这里可以检查该功能是否可用。

答案 4 :(得分:0)

我发现jquery.floatThead确实可以满足我的需求,但我只是缺少此设置:

$("table").floatThead({
position:"absolute"
});

默认为“固定”,在这种情况下不起作用。

您可以看到固定的小提琴here,它完全按照我的需要工作。

不过,我需要一个javascript包来完成如此简单的任务,这有​​点荒谬。如果我遗漏了一些东西,并且对这个基本问题有一个更简单的答案,我很想听听! ?