目标位置: 当前处于“卡住”状态的粘性元素

位置: 粘性 现在可以在一些移动浏览器上工作,所以你可以让菜单栏随着页面滚动,但是当用户滚动时,粘附在视窗的顶部。

但是,如果你想重新设计你的粘性菜单栏,只要它目前“粘”?例如,你可能希望在滚动页面的时候工具条有圆角,但是一旦它粘在视图的顶部,你就想去掉顶部的圆角,在它下面添加一个小的阴影。

是否有任何类型的伪选择器(例如 ::stuck)目标元件有 position: sticky 还有目前粘贴?或者浏览器供应商有类似的产品吗?如果没有,我在哪里申请?

注意。Javascript 解决方案对此并不好,因为在移动设备上,当用户松开手指时,通常只能获得一个 scroll事件,所以 JS 无法知道滚动阈值通过的确切时间。

57944 次浏览

目前还没有为当前“卡住”的元素提供选择器。定义 position: sticky定位布局模块也没有提到任何这样的选择器。

对 CSS 的特性请求可以发布到 Www 风格的邮件列表。我相信 :stuck伪类比 ::stuck伪元素更有意义,因为您要在元素处于这种状态时瞄准元素本身。事实上,我们讨论过 :stuck伪类 不久之前; 我们发现,主要的复杂情况是,几乎所有试图基于呈现或计算样式进行匹配的选择器都会遇到这样的问题: 循环依赖。

:stuck伪类的情况下,最简单的循环情况会发生在以下 CSS 中:

:stuck { position: static; /* Or anything other than sticky/fixed */ }
:not(:stuck) { position: sticky; /* Or fixed */ }

而且可能会有更多难以处理的边缘案例。

虽然人们普遍认为,基于某些布局状态匹配的选择器应该是 不错,但不幸的是,主要的限制存在,使得这些选择器的实现非常重要。对于这个问题的纯 CSS 解决方案,我不会抱太大希望。

我并不喜欢使用 js hacks 来设计样式(例如 getBoudingClientRect,滚动聆听,调整聆听的大小) ,但这是我目前解决这个问题的方法。这个解决方案将有问题的页面,具有最小化/最大化的内容(< Details >) ,或嵌套滚动,或实际上任何曲线球等。也就是说,当问题也很简单时,这是一个简单的解决方案。

let lowestKnownOffset: number = -1;
window.addEventListener("resize", () => lowestKnownOffset = -1);


const $Title = document.getElementById("Title");
let requestedFrame: number;
window.addEventListener("scroll", (event) => {
if (requestedFrame) { return; }
requestedFrame = requestAnimationFrame(() => {
// if it's sticky to top, the offset will bottom out at its natural page offset
if (lowestKnownOffset === -1) { lowestKnownOffset = $Title.offsetTop; }
lowestKnownOffset = Math.min(lowestKnownOffset, $Title.offsetTop);
// this condition assumes that $Title is the only sticky element and it sticks at top: 0px
// if there are multiple elements, this can be updated to choose whichever one it furthest down on the page as the sticky one
if (window.scrollY >= lowestKnownOffset) {
$Title.classList.add("--stuck");
} else {
$Title.classList.remove("--stuck");
}
requestedFrame = undefined;
});
})

Google Developers 博客 上有人声称已经找到了一个使用 十字路口,观察者的基于 JavaScript 的性能解决方案。

相关代码:

/**
* 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));
}

我没有自己复制它,但也许它帮助某人在这个问题上磕磕绊绊。

在某些情况下,一个简单的 IntersectionObserver可以做到这一点,如果情况允许坚持在其根容器之外的一个或两个像素,而不是正确地对齐。这样当它刚好在边缘时,观察者就会开火,我们就可以开始跑了。

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


observer.observe(document.querySelector('nav'));

top: -2px将元素从容器中粘贴出来,然后通过 stuck属性定位..。

nav {
background: magenta;
height: 80px;
position: sticky;
top: -2px;
}
nav[stuck] {
box-shadow: 0 0 16px black;
}

例如: https://codepen.io/anon/pen/vqyQEK

一个紧凑的方法,当你有一个元素以上的 position:sticky元素。它设置属性 stuck,您可以在 CSS 中将其与 header[stuck]匹配:

HTML:

<img id="logo" ...>
<div>
<header style="position: sticky">
...
</header>
...
</div>

约翰逊:

if (typeof IntersectionObserver !== 'function') {
// sorry, IE https://caniuse.com/#feat=intersectionobserver
return
}


new IntersectionObserver(
function (entries, observer) {
for (var _i = 0; _i < entries.length; _i++) {
var stickyHeader = entries[_i].target.nextSibling
stickyHeader.toggleAttribute('stuck', !entries[_i].isIntersecting)
}
},
{}
).observe(document.getElementById('logo'))

我想要一个纯粹的 CSS 解决方案,允许样式化一个“卡住”的元素,仿佛一个 ::stuck伪选择器存在(唉,仍然不在2021年)。

我已经创建了一个纯 CSS 黑客,实现了没有 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>

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;
}