javascript - 如何在没有 JavaScript 的情况下使元素相对于窗口具有粘性(如果可能)?

标签 javascript html css

我一直很喜欢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。

chrome profiling 4x slowdown

关于javascript - 如何在没有 JavaScript 的情况下使元素相对于窗口具有粘性(如果可能)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53550603/

相关文章:

javascript - 如何在同一页面而不是弹出窗口中打开 chrome 应用程序?

c# - 尝试从 MVC 中新打开的窗口返回上一个 View

javascript - 创建一个基于 JavaScript 的内存游戏

html - 如果表的第二列太长,则使第一列跨度

CSS:背景图像拉伸(stretch)和挤压到 div 的 100% 区域,没有溢出,没有重复

javascript - 谷歌图书 API : Cannot read property 'thumbnail' of undefined

javascript - 事件监听器是否与 html 事件相同?

javascript - 响应式导航干扰其他代码元素

javascript - 为什么滚动动画没有被禁用?

javascript - 错误: Cannot find module 'loopback' in nodejs