仅使用CSS能否实现双内部滚动联动的固定表头表格?
需求说明
为更好说明场景,制作了如下示意图:
需求具体如下:
- 左右列可同步垂直滚动,表头始终固定在顶部,不会跟随垂直滚动位移
- 右列水平滚动时,左列表头同步水平滚动
- 整个组件包裹在单个
<div>内,不能用position: sticky(该属性仅基于浏览器窗口生效),表格高度固定,浏览器窗口无滚动条
现有尝试代码
CSS代码
* { box-sizing: border-box; } .columns { width: 796px; border: 2px solid green; height: 200px; overflow-y: scroll; display: flex; } .left-col { width: 200px; border: 2px solid yellow; } .right-col { width: 600px; height: 200px; border: 2px solid brown; overflow-y: auto; overflow-x: auto; } .filler-y { height: 1200px; width: 10px; background-color: red; } .filler-both { width: 2000px; height: 2000px; background-color: red; }
HTML代码
<div class="columns"> <div class="left-col"> leftcol <div class="filler-y"></div> </div> <div class="right-col"> right col <div class="filler-both"></div> </div> </div>
解决方案
这个需求单靠CSS无法实现,需要配合少量JS处理滚动同步逻辑,调整方案如下:
- 先把表头和表格内容拆分为独立模块,表头容器固定在组件顶部,脱离左右列滚动流
- 给左右列内容容器绑定垂直滚动监听,任意一侧滚动时同步设置另一侧的
scrollTop,实现垂直滚动同步 - 给右列内容容器绑定水平滚动监听,滚动时同步设置左列表头的
scrollLeft,实现水平滚动联动 - 去掉最外层容器的
overflow-y: scroll,垂直滚动逻辑完全交给左右列内容容器处理,避免外层滚动带动表头位移
调整后的核心实现代码:
调整后CSS
* { box-sizing: border-box; } /* 外层总容器 */ .table-wrap { width: 796px; border: 2px solid green; height: 200px; display: flex; flex-direction: column; } /* 表头容器 */ .table-header { display: flex; width: 100%; overflow-x: hidden; } .left-header { width: 200px; border: 2px solid yellow; flex-shrink: 0; } .right-header { flex: 1; overflow-x: hidden; border: 2px solid brown; } /* 内容容器 */ .table-body { flex: 1; display: flex; overflow: hidden; } .left-body { width: 200px; border: 2px solid yellow; overflow-y: auto; flex-shrink: 0; } .right-body { flex: 1; overflow: auto; border: 2px solid brown; } /* 填充元素仅做高度/宽度测试用 */ .filler-y { height: 1200px; width: 10px; background-color: red; } .filler-both { width: 2000px; height: 2000px; background-color: red; }
调整后HTML
<div class="table-wrap"> <!-- 表头区域 --> <div class="table-header"> <div class="left-header">左列表头</div> <div class="right-header">右列表头</div> </div> <!-- 内容区域 --> <div class="table-body"> <div class="left-body"> 左列内容 <div class="filler-y"></div> </div> <div class="right-body"> 右列内容 <div class="filler-both"></div> </div> </div> </div>
同步滚动JS逻辑
const leftBody = document.querySelector('.left-body') const rightBody = document.querySelector('.right-body') const leftHeader = document.querySelector('.left-header') // 垂直滚动同步 let isSyncingV = false leftBody.addEventListener('scroll', () => { if (isSyncingV) return isSyncingV = true rightBody.scrollTop = leftBody.scrollTop isSyncingV = false }) rightBody.addEventListener('scroll', () => { if (isSyncingV) return isSyncingV = true leftBody.scrollTop = rightBody.scrollTop isSyncingV = false }) // 水平滚动同步左列表头 rightBody.addEventListener('scroll', () => { leftHeader.scrollLeft = rightBody.scrollLeft })
该方案完全符合所有需求:表头始终固定在顶部不会跟随滚动,左右列垂直滚动完全同步,右列水平滚动时左列表头也会同步滚动,所有逻辑都包裹在单个外层<div>内,未使用position: sticky属性。
内容的提问来源于stack exchange,提问作者Ovidiu Pistol
相关产品推荐
相关产品推荐

