在水平滚动表上固定表头
在水平滚动表上固定表头
你会认为这很容易。但事实并非如此。
第 0 章:环境
整篇文章都基于一个 React 应用程序,因此虽然它不是强制性的,但如果您至少具备 React 和 React Hooks 的基本知识,它会有所帮助。
第 1 章:最初的问题
在我们最近开展的一个项目中,我们面临一个非常具体的问题:客户想要一张大桌子。
我是什么意思 大的 ?好吧,我见过有 15 列以上的表格 很多 比屏幕宽。幸运的是,这不是其中一张桌子,但无论如何它都比可用空间宽。
除此之外,表格还需要具有易于滚动的按钮。
为了实现这一点,我们将表格包裹在一个 <div>
有它的 宽度
锁定到特定值(例如屏幕宽度的 80%)。然后我们添加了一些按钮和一个 滚动
改变包装器滚动位置的函数。滚动功能看起来像这样:
这导致了一个带有水平滚动条的漂亮表格以及在没有触摸板的情况下可以滚动的按钮。
这很好,并且按预期工作。
第 2 章:新需求出现
此状态下的表已获批准并部署到生产环境。一切看起来都很好,直到一些用户开始要求我们在滚动时将标题固定在顶部。这样他们就可以识别每个值是什么,而无需来回滚动来检查列名。
我们的第一直觉是我认为大多数人会做的事情:我们补充说 位置:粘性
到 头
表的元素。
这似乎太容易了,对吧?那是因为它是,请看看当我们这样做时会发生什么:
我们可以看到表格元素有效地具有 位置:粘性
属性,但在滚动一点后,它们会离开屏幕。
这是因为,根据 CSS 规范 :
此值始终创建一个新的堆叠上下文。请注意,粘性元素“粘”到它最近的具有“滚动机制”的祖先(当溢出被隐藏、滚动、自动或覆盖时创建),即使该祖先不是最近的实际滚动祖先。
所以这里的问题是:
.layout__content
正在滚动。.table__wrapper
不滚动。.table 头
相对于.table_wrapper
.
我们想要的是 .table 头
相对于 .layout__content
.这是不可能的,因为即使 .table__wrapper
只有 溢出-x
指定它仍然有一个 溢出
财产,所以 .table 头
而是坚持下去。
第 3 章:第一种方法
因此,考虑到规格,让我们删除 溢出-x
从 .layout__content
看看会发生什么。
那么会发生什么?
所以,看起来它奏效了……还是真的奏效了?
不好了!我们的滚动按钮停止工作。不仅如此,现在滚动表格还会滚动整个页面,包括标题。那不应该发生。
但是,嘿!至少我们的标题现在是固定的!
第四章:别告诉我该怎么做!
因此,在寻找解决方案(并且摸不着头脑)很长一段时间后,我们想出了一个解决手头问题的方法:让我们使用 JavaScript 和 CSS!
基本思想是这样的:
- 让我们看看表头在哪里。
- 让我们看看用户向下滚动了多远。一个。如果用户滚动到标题开始下方,让我们
翻译
这头
元素,所以它保持在顶部。湾。如果没有,请删除翻译
表头的属性。
因为我们在这个应用程序中使用了 React,所以我们使用了一些 参考
跟踪实际的 DOM 元素。
代码看起来像这样(我把它写成一个可重用的钩子):
让我们分解代码:
首先,我们声明了两个 ref,一个用于表包装器,一个用于表头。
你可能会问 为什么 我们为表包装器而不是表本身声明一个 ref。这背后的原因是,在代码的更下方,我们使用一些定位来计算用户滚动了多少,并且 偏移顶部
是相对于父级的,所以表总是有一个 偏移顶部
相对于其父级(包装器)等于零。包装器应该是滚动元素的直接子元素(在我们的例子中, 布局__内容
元素)。
然后我们写一个 使用效果
负责向滚动元素添加事件侦听器的钩子,以便当它滚动时我们采取相应的行动。
我们的意思是什么 相应地采取行动 ?好吧,我们应该检查标题相对于滚动元素的位置,但是当我们要移动它时,我们应该检查表格位置,这就是我们使用表格包装器的地方,因为该元素不会相对于内容元素。从那时起,我们可以看到父元素是否已经滚动到标题位置,如果是,我们 翻译
那个滚动位置差异的元素( 滚动位置
- 标题位置
)。如果滚动位置高于标题位置,我们只需将其删除 翻译
财产。
记住删除该事件侦听器也很重要,否则在导航到应用程序的另一个部分后,我们可能会引用不再存在的元素,并且应用程序会崩溃。为了实现这一点,我们返回一个函数,该函数在我们的 使用效果
.
所以, 成功了吗 ?
是的!它不是 100% 完美的,标题可能会跳跃一点,但这是因为事件循环,但这超出了这篇博文的范围。
但是开发工具中会弹出一些东西:
在该链接之后,我们看到 Firefox 推荐 使用 位置:粘性
对于我们正在做的事情。
好吧,Firefox,我们会使用 位置:粘性
如果它像我们希望的那样工作。
最后的想法
解决这个问题非常有趣,但我认为如果 CSS 规范能够考虑到这一点会很好。也许有一个属性叫做 粘性锚
有价值观 “祖先” | “屏幕”
会好的。我认为 祖先
将保持当前行为(并成为默认值)和 屏幕
只会考虑整个屏幕。如果是这种情况,我们将能够跳过所有代码,只使用这样的 CSS:
此外,这种方法不是最好的,滚动到快速或中低端设备会导致标题出现一些抖动,所以如果你需要一个 100% 完美的解决方案,你应该查看事件循环和动画循环会更好。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明