KP8*_*P83 7 html javascript css intersection-observer
我从scroll event
方法开始这个问题,但是由于建议使用IntersectionObserver
似乎更好的方法,因此我试图以这种方式使其工作。
目标是什么:
我想改变风格(color
+ background-color
中的)header
这取决于电流div
/ section
通过查找(我在想的?),观察其class
或data
将覆盖默认header
样式(黑白色)。
标头样式:
font-color
:
根据内容(div
/ section
),默认值header
应该只能将font-color
变为两种可能的颜色:
background-color
:
根据内容的不同,background-color
颜色可能是无限的,也可能是透明的,因此最好将它们分开处理,这些可能是最常用的背景颜色:
CSS:
header {
position: fixed;
width: 100%;
top: 0;
line-height: 32px;
padding: 0 15px;
z-index: 5;
color: black; /* default */
background-color: white; /* default */
}
Run Code Online (Sandbox Code Playgroud)
默认标题的Div / section示例,内容无变化:
<div class="grid-30-span g-100vh">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
data-src="/images/example_default_header.jpg"
class="lazyload"
alt="">
</div>
Run Code Online (Sandbox Code Playgroud)
Div / section示例更改内容标题:
<div class="grid-30-span g-100vh" data-color="white" data-background="darkblue">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
data-src="/images/example_darkblue.jpg"
class="lazyload"
alt="">
</div>
<div class="grid-30-span g-100vh" data-color="white" data-background="black">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
data-src="/images/example_black.jpg"
class="lazyload"
alt="">
</div>
Run Code Online (Sandbox Code Playgroud)
交叉口观察员方法:
var mq = window.matchMedia( "(min-width: 568px)" );
if (mq.matches) {
// Add for mobile reset
document.addEventListener("DOMContentLoaded", function(event) {
// Add document load callback for leaving script in head
const header = document.querySelector('header');
const sections = document.querySelectorAll('div');
const config = {
rootMargin: '0px',
threshold: [0.00, 0.95]
};
const observer = new IntersectionObserver(function (entries, self) {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (entry.intersectionRatio > 0.95) {
header.style.color = entry.target.dataset.color !== undefined ? entry.target.dataset.color : "black";
header.style.background = entry.target.dataset.background !== undefined ? entry.target.dataset.background : "white";
} else {
if (entry.target.getBoundingClientRect().top < 0 ) {
header.style.color = entry.target.dataset.color !== undefined ? entry.target.dataset.color : "black";
header.style.background = entry.target.dataset.background !== undefined ? entry.target.dataset.background : "white";
}
}
}
});
}, config);
sections.forEach(section => {
observer.observe(section);
});
});
}
Run Code Online (Sandbox Code Playgroud)
而不是听滚动事件,您应该看看Intersection Observer(IO)。旨在解决您的问题。它比聆听滚动事件然后自己计算位置要好得多。
首先,这是一个Codepen,它显示了您的问题的解决方案。我不是该Codepen的作者,我可能会做一些不同的事情,但是它肯定向您显示了解决问题的基本方法。
我将要更改的内容:在示例中,您可以看到,如果将99%的内容添加到新部分中,则标题的更改甚至变得很困难,新部分也不是完全可见的。
现在解决了这个问题,对它的工作原理进行了一些解释(请注意,我不会盲目地从codepen复制粘贴,我还将const更改为let,而是使用更适合您的项目的东西。
首先,您必须指定IO选项:
let options = {
rootMargin: '-50px 0px -55%'
}
let observer = new IntersectionObserver(callback, options);
Run Code Online (Sandbox Code Playgroud)
在该示例中,一旦元素距离视图50px,IO将执行回调。我不能一味推荐一些更好的值,但如果有时间,我会尝试调整这些参数以查看是否可以获得更好的结果。
他们在codepen中定义了内联的回调函数,我只是用这种方式编写了它,以便更清楚地了解发生在什么地方。
IO的下一步是定义一些要监视的元素。在您的情况下,您应该在div中添加一些类,例如<div class="section">
let entries = document.querySelectorAll('div.section');
entries.forEach(entry => {observer.observe(entry);})
Run Code Online (Sandbox Code Playgroud)
最后,您必须定义回调函数:
entries.forEach(entry => {
if (entry.isIntersecting) {
//specify what should happen if an element is coming into view, like defined in the options.
}
});
Run Code Online (Sandbox Code Playgroud)
编辑:正如我所说的,这只是一个如何入门的示例,它不是复制粘贴的最终解决方案。在基于可见部分的示例中,当前元素被突出显示。您必须更改此部分,以便不要将活动类设置为例如第三个元素,而是根据在Element上设置的某些属性来设置颜色和背景色。我建议为此使用数据属性。
编辑2:当然,您可以继续使用滚动事件,W3C 的官方Polyfill使用滚动事件来模拟旧版浏览器的IO,只是侦听滚动事件和计算位置效果不佳,尤其是在有多个元素的情况下。因此,如果您关心用户体验,我真的建议您使用IO。只是想添加此答案,以显示针对该问题的现代解决方案。
编辑3:我花了一些时间来创建基于IO的示例,这应该使您入门。
基本上,我定义了两个阈值:一个为20%,一个为90%。如果元素在视口中占90%,则保存它会覆盖标题。因此,我将标题的类设置为视图中90%的元素。
第二个阈值是20%,这里我们必须检查元素是从顶部还是从底部进入视图。如果从顶部可见20%,则它将与标题重叠。
调整这些值并调整逻辑,如您所见。
let options = {
rootMargin: '-50px 0px -55%'
}
let observer = new IntersectionObserver(callback, options);
Run Code Online (Sandbox Code Playgroud)
let entries = document.querySelectorAll('div.section');
entries.forEach(entry => {observer.observe(entry);})
Run Code Online (Sandbox Code Playgroud)
entries.forEach(entry => {
if (entry.isIntersecting) {
//specify what should happen if an element is coming into view, like defined in the options.
}
});
Run Code Online (Sandbox Code Playgroud)
我可能不完全理解这个问题,但对于你的例子 - 你可以通过使用mix-blend-mode css 属性来解决它,而不需要使用 javascript。
例子:
header {background: white; position: relative; height: 20vh;}
header h1 {
position: fixed;
color: white;
mix-blend-mode: difference;
}
div {height: 100vh; }
Run Code Online (Sandbox Code Playgroud)
<header>
<h1>StudioX, Project Title, Category...</h1>
</header>
<div style="background-color:darkblue;"></div>
<div style="background-color:lightgrey;"></div>
Run Code Online (Sandbox Code Playgroud)