我一直很喜欢position: sticky
.它无需诉诸 JavaScript 即可解决大部分(如果不是全部)问题。但是,我碰壁了。我需要制作一个嵌套在几个 <div>
中的元素要粘。我们知道 position: sticky
作为 position: relative
的混合物使用和 position: fixed
,因此它将锚定到它的第一个父级。
来自 MDN :
The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor)
在这种情况下,我想让标题相对于窗口而不是容器具有粘性。 HTML 让我很难在嵌套 <div>
之外重组它
如果没有 JavaScript,这可能吗?
代码如下:
<div class="attendance">
<!-- Here's the header I want to make sticky to the window, and not to div.attendance-->
<header class="text-center sticky">Monday 11/22/2019</header>
<!-- Header above -->
<div class="date-config">
<div class="form-group">
<input type="checkbox" id="workable" /> No Work<br />
</div>
<div class="form-group">
<label for="notes">Notes:</label>
<textarea id="notes" class="form-control"></textarea>
</div>
<label for="markall">Mark all as>
<select id="markall" class="form-control">
<option></option>
<option>Absent</option>
<option>Present</option>
</select>
</div>
<div class="student-attendance">
Hello :)
</div>
</div>
有什么想法吗?
P.S:我找到了this ,但它使用 JavaScript。
编辑: Here's an awful, but working example (当心!它是西类牙语 - 寻找日期!它们不会粘在 window 上!)。
最佳答案
好的!首先,我想道歉,因为如果不呈现 HTML 就无法回答这个问题。幸运的是,我找到了解决方案。
TL;DR 在这种情况下,不,您需要 JavaScript。您将需要实现 translateY
在元素中进行转换以实现此目的。不知道是不是父元素有transform属性导致的问题this bug或者是其他原因导致了这个问题。
解释:
我目前正在使用一个名为 tiny slider 的轮播 JS 库.我正在显示表单元素而不是图像,(构建一个响应表;当我尝试使用 CSS 网格时遇到问题)。到目前为止,一切都很好。当我想设置 sticky
时问题就开始了日期标题。
我采用现代方法设置 position:sticky
,但这没有用。这些元件会堵塞在某个位置,并且不会移动或粘住。我开始在线研究(最终问了同样的问题)和 HTML 本身。我确实发现有很多 parent <div>
由 tiny-slider 创建的。我的理论是它对其中一位 parent 产生了依恋。
因此,我决定尝试结合 position:fixed
的老策略。用scroll
事件。但是,那没有用。重新上网谷歌了一下,好像有个老bug [1] [2] [3]每当对其中一个父项应用翻译时,就会创建一个根外容器,并且 position:fixed
没有按预期工作。
我有预感这可能是粘性不起作用的原因之一,但根据 this answer ,好像不是。
想了想,还是用了transform
带有 translateY
的 CSS 属性.我在浏览器中做了一个小实验,成功了!
因此,我最终实现了 scroll
eventListener 并监听 header 的父级位置,并应用 getBoundingClientRect() 来获取偏移量。如果我将它应用到元素本身,它会给我通过 CSS 应用的翻译位置。
我怀疑这可能是移动浏览器的性能瓶颈。因此,我检查了在 requestAnimationFrame
中调用了转换函数。它应用了 will-change
CSS 样式表中的属性。
我在 Google Chrome 中以 4 倍的 CPU 减速运行代码,并取得了良好的结果 😁。
这是我得到的函数(其中 elemsToFixed 是所有 <header>
元素,threshold 是顶部偏移量,因此它不会与导航栏冲突):
export function fixedHeaderScroll(elemsToFixed: HTMLHeadingElement[], threshold: number) {
if (!elemsToFixed || elemsToFixed.length === 0) {
console.error("elemsToFixed can't be null or empty");
return;
}
console.log('Total elems', elemsToFixed.length);
// We assume that all of the elements are on the same height.
const firstEl = elemsToFixed[0];
let propSet = false;
window.addEventListener('scroll', (e) => {
window.requestAnimationFrame(() => {
const top = firstEl.parentElement!.getBoundingClientRect().top;
if (top > threshold) {
if (!propSet) return;
propSet = false;
setElemsFixed(elemsToFixed, top, threshold, false);
return;
}
propSet = true;
setElemsFixed(elemsToFixed, top, threshold);
});
});
}
function setElemsFixed(elemsToFixed: HTMLHeadingElement[], top: number,
threshold: number, setFixed = true) {
console.log('SetElemsFixed is', setFixed);
elemsToFixed.forEach((elem) => {
if (!setFixed) {
elem.removeAttribute('style');
return;
}
elem.style.transform = `translateY(${(top * -1)}px)`;
});
}
下图显示 CPU 速度降低了 4 倍,样式(包含 26 个元素)的计算时间约为 29.4 毫秒(太棒了!)。在 Windows 和 i7 4700MQ 处理器上使用 Chrome 70。
关于javascript - 如何在没有 JavaScript 的情况下使元素相对于窗口具有粘性(如果可能)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53550603/