定位位置:当前处于"卡住"状态的粘性元素

cal*_*lum 83 css css-position css-selectors css3

position:sticky现在可以在某些移动浏览器上运行,因此您可以使菜单栏与页面一起滚动,但只要用户滚过它就会粘到视口顶部.

但是,如果您想要在粘贴的菜单栏中稍微重新设置,只要它现在"粘住",该怎么办?例如,您可能希望条形图在滚动页面时具有圆角,但是一旦它粘贴到视口顶部,您就想要摆脱顶部圆角,并在下面添加一点阴影它.

是否存在任何类型的伪选择器(例如::stuck)来定位具有position: sticky 并且当前正在粘附的元素?或者浏览器供应商在管道中有这样的东西吗?如果没有,我会在哪里申请?

NB.javascript解决方案对此不利,因为在移动设备上,scroll当用户松开手指时,通常只会收到一个事件,因此JS无法知道滚动阈值通过的确切时刻.

Bol*_*ock 83

目前没有针对当前"卡住"的元素提出选择器.所述Postioned布局模块,其中position: sticky被定义不任一提及任何此类选择器.

CSS的功能请求可以发布到www样式的邮件列表中.我相信:stuck伪类比::stuck伪元素更有意义,因为你希望在它们处于该状态时将元素本身作为目标.事实上,前一段时间:stuck讨论过一个伪类; 发现的主要复杂因素是,任何基于渲染或计算样式尝试匹配的任何提议的选择器都会受到困扰:循环依赖.

:stuck伪类的情况下,使用以下CSS会出现最简单的圆形情况:

:stuck { position: static; /* Or anything other than sticky/fixed */ }
:not(:stuck) { position: sticky; /* Or fixed */ }
Run Code Online (Sandbox Code Playgroud)

并且可能存在更多难以解决的边缘情况.

虽然人们普遍认为,根据某些布局状态选择匹配的选择器会很好,但遗憾的是存在一些主要的限制因素,这些限制使这些非常重要.我不会很快屏住这个问题的纯CSS解决方案.

  • 我相信可以使用许多已经存在的伪类进行相同的循环问题(例如:悬停改变宽度并且:not(:hover)再次改回).我很想:卡住伪类并认为开发人员应该对他的代码中没有循环问题负责. (18认同)
  • 嗯...我真的不明白这是错误 - 这就像说'while`循环设计糟糕,因为它允许无限循环:)但是感谢清除它;) (11认同)
  • 真是太遗憾了.我也在寻找这个问题的解决方案.简单地引入一个规则,说``stuck`选择器上的`position`属性应该被忽略,这不是很容易吗?(我的意思是浏览器供应商的规则,类似于关于`left`优先于`right`等的规则) (10认同)
  • 这不仅仅是位置...想象一个`:卡住'将`top`值从'0`改为`300px`,然后向下滚动`150px` ......它应该坚持还是不坚持?或者考虑一个带有`position:sticky`和`bottom:0`的元素,其中`:stuck`可能会改变`font-size`,从而改变元素大小(因此改变它应该坚持的时刻)...... (3认同)
  • 请参阅https://github.com/w3c/csswg-drafts/issues/1660,其中的建议是让JS事件知道什么时候卡住/解开.这不应该有伪选择器引入的问题. (3认同)
  • @BoltClock 是的,它看起来有问题。使用复杂的技术创建错误行为的可能性并不是完全禁用(非常需要的)功能的理由。例如,能够在“<ul>”内输入“<div>”(而不是“<li>”)并不是要一起丢弃列表的理由,不是吗? (3认同)
  • @LazarLjubenović这是一篇博客文章,其中包含您可以在过渡期间使用的黑客文章:https://developers.google.com/web/updates/2017/09/sticky-headers (2认同)
  • 如果 ie4 可以支持 `:hover{display:none;}` 我相信现代浏览器不会因为 `:stuck{position:static;}` 而爆炸 (2认同)
  • @BoltClock 这只是一个比喻。这是另一个 - 我们是否应该取消 JS 中的循环,因为可以执行无限循环?在执行`:stuck{position:static}` 时,元素会像疯了一样闪烁 - 就这样吧。无论如何它都不应该发生,人们只是希望 :stuck 设置 box-shadow 或通过检查 `scroll` 事件上的 `.is(':stuck')` 来更改某些元素。 (2认同)
  • @oriadam 和 MarekLisý 提到的无限循环示例对我来说似乎是一个很好的比较。我不明白为什么 CSS 需要防止开发人员编写糟糕的代码。是否存在某种技术原因导致实现此类功能不可能或成本过高?开发人员可能会犯错误这一事实肯定不能成为原因。 (2认同)
  • `:stuck` 可以忽略位置属性吗?大多数情况下它只是用来添加一个怪异的阴影...... (2认同)

Tom*_*ony 9

我想要一个纯 CSS 解决方案,允许为“卡住”元素设置样式,就好像存在::stuck伪选择器一样(唉,2021 年还没有)。

我创建了一个纯 CSS hack,无需 JS 即可实现效果并满足我的需求。它的工作原理是拥有元素的两个副本,一个是sticky,另一个不是(unstuck一个),后一个覆盖sticky元素,直到您滚动它为止。

演示:https : //codepen.io/TomAnthony/pen/qBqgErK

替代演示:https : //codepen.io/TomAnthony/pen/mdOvJYw(这个版本更符合我的要求,我希望粘性项目仅在“卡住”时出现 - 这也意味着没有重复的内容。)

HTML:

<div class="sticky">
    <div class="unstuck">
        <div>
        Box header. Italic when 'stuck'.
        </div>
    </div>
    <div class="stuck">
        <div>
        Box header. Italic when 'stuck'.
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

CSS:

.sticky {
    height: 20px;
    display: inline;
    background-color: pink;
}

.stuck {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    height: 20px;
    font-style: italic;
}

.unstuck {
    height: 0;
    overflow-y: visible;
    position: relative;
    z-index: 1;
}

.unstuck > div {
    position: absolute;
    width: 100%;
    height: 20px;
    background-color: inherit;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案,因为它不含 JS。如果文本重复,还应该将 `aria-hidden=true` 设置为其中之一,以避免可访问性胡言乱语。更好的解决方案可能是将重复内容放入 `data-content="..."` 和样式中:after 元素带有 `content: attr(data-content)`。不过我还没有尝试过 (2认同)

rac*_*ble 8

在某些情况下IntersectionObserver,如果情况允许在其根容器之外粘贴一个或两个像素,而不是对其进行适当冲洗,则简单的方法就可以解决问题。这样,当它正好位于边缘之外时,观察者就会开火,我们可以出发并奔跑了。

const observer = new IntersectionObserver( 
  ([e]) => e.target.toggleAttribute('stuck', e.intersectionRatio < 1),
  {threshold: [1]}
);

observer.observe(document.querySelector('nav'));
Run Code Online (Sandbox Code Playgroud)

使用将该元素刚从其容器中伸出top: -2px,然后通过stuck属性进行定位...

nav {
  background: magenta;
  height: 80px;
  position: sticky;
  top: -2px;
}
nav[stuck] {
  box-shadow: 0 0 16px black;
}
Run Code Online (Sandbox Code Playgroud)

此处的示例:https : //codepen.io/anon/pen/vqyQEK

  • 类也可以正常工作,但这似乎比那要高一点,因为它是派生属性。一个属性对我来说似乎更合适,但无论哪种方式,这都是一个品味问题。 (4认同)
  • 我认为“卡住”类会比自定义属性更好...您的选择有什么具体原因吗? (2认同)
  • 向元素添加无效的 HTML5 属性只是“不是”品味问题。我强烈建议您修改并承认@collimarco 的评论。 (2认同)

neo*_*ern 6

Google Developers 博客上的某个人声称已经找到了一个基于 JavaScript 的执行性解决方案,其中包含IntersectionObserver

相关代码位在这里:

/**
 * Sets up an intersection observer to notify when elements with the class
 * `.sticky_sentinel--top` become visible/invisible at the top of the container.
 * @param {!Element} container
 */
function observeHeaders(container) {
  const observer = new IntersectionObserver((records, observer) => {
    for (const record of records) {
      const targetInfo = record.boundingClientRect;
      const stickyTarget = record.target.parentElement.querySelector('.sticky');
      const rootBoundsInfo = record.rootBounds;

      // Started sticking.
      if (targetInfo.bottom < rootBoundsInfo.top) {
        fireEvent(true, stickyTarget);
      }

      // Stopped sticking.
      if (targetInfo.bottom >= rootBoundsInfo.top &&
          targetInfo.bottom < rootBoundsInfo.bottom) {
       fireEvent(false, stickyTarget);
      }
    }
  }, {threshold: [0], root: container});

  // Add the top sentinels to each section and attach an observer.
  const sentinels = addSentinels(container, 'sticky_sentinel--top');
  sentinels.forEach(el => observer.observe(el));
}
Run Code Online (Sandbox Code Playgroud)

我自己没有复制它,但也许它可以帮助那些在这个问题上绊倒的人。