javascript - 根据背景颜色滚动时更改 SVG 填充
问题描述
我正在构建一个React
网站,该网站在滚动section
时使用面板向上滑动,但在元素及其与.position: sticky
fixed
color
section
background-color
这是问题的一个简单片段。
html {
font-family: sans-serif;
font-size: 20px;
font-weight: 700;
text-transform: uppercase;
}
*,
::after,
::before {
box-sizing: border-box;
}
body {
margin: 0;
overflow-x: hidden;
}
.nav {
position: fixed;
width: 100;
top: 0;
left: 0;
right: 0;
padding: 24px 28px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
svg {
fill: black; // Change to white over dark backgrounds
}
.sticky {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: sticky;
top: -1px;
}
.dark {
background-color: #1e1e1e;
color: #fff;
}
<div class="nav"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="32px" id="Layer_1" style="enable-background:new 0 0 32 32;" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve"><path d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z M28,14H4c-1.104,0-2,0.896-2,2 s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2 S29.104,22,28,22z"/></svg></div>
<main>
<div class="sticky">Section Light</div>
<div class="sticky dark">Section Dark</div>
</main>
当覆盖元素定位为 时,我已经看到了其他示例,但是由于每个面板使用absolute
的位置,它们在这种情况下不起作用。此外,由于某些部分使用背景图像,因此无法使用,这看起来很糟糕。sticky
section
mix-blend-mode
其次,网站是内置的Gatsby
,React
我可以访问每个部分的背景颜色。
滚动不同的背景颜色时如何更改menu
svg 的颜色?我只想要白色或黑色。
解决方案
我们可以使用 intersectionObserver 来告诉我们新部分何时接近视口顶部,并相应地更改菜单图标的颜色。相反,当一个部分从顶部附近出来时,根据其前一个兄弟元素(即下面的元素)的黑暗状态更改菜单。
这个片段展示了:
const svg = document.querySelector('svg');
let callback = (entries, observer) => {
entries.forEach(entry => {
//List from MDN:
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
//eventually make the gradient chosen depend on the % overlap and the color of the previous sibling element
if (entry.isIntersecting) {
svg.style.fill = (entry.target.classList.contains('dark')) ? 'url(#white)' : 'url(#black)';
}
else {
svg.style.fill = (entry.target.previousElementSibling.classList.contains('dark')) ? 'url(#white)' : 'url(#black)';
}
});
};
let options = {
threshold: [ 0.9, 0.94, 0.98 ] // need to work on these thresholds
}
let observer = new IntersectionObserver(callback, options);
const stickies = document.querySelectorAll('main div.sticky');
stickies.forEach( sticky => {
observer.observe(sticky);
});
html {
font-family: sans-serif;
font-size: 20px;
font-weight: 700;
text-transform: uppercase;
}
*,
::after,
::before {
box-sizing: border-box;
}
body {
margin: 0;
overflow-x: hidden;
}
.nav {
position: fixed;
width: 100;
top: 0;
left: 0;
right: 0;
rpadding: 24px 28px;
padding: 2vh 28px;
rpadding: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
z-index: 999;
}
svg {
fill: black;
}
.sticky {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: sticky;
top: -1px;
background-color: white;
}
.dark {
background-color: #1e1e1e;
color: #fff;
}
<div class="nav">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="32px" id="Layer_1" style="enable-background:new 0 0 32 32;" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve">
<defs>
<linearGradient id="black" x1="0%" y1="0%" x2="100%" y2="0%" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="#000"/>
<stop offset="100%" stop-color="#000"/>
</linearGradient>
<linearGradient id="white" x1="0%" y1="0%" x2="100%" y2="0%" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="#fff"/>
<stop offset="100%" stop-color="#fff"/>
</linearGradient>
</defs>
<path d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z M28,14H4c-1.104,0-2,0.896-2,2 s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2 S29.104,22,28,22z"/>
</svg>
</div>
<main>
<div class="sticky">Section 1 Light</div>
<div class="sticky dark">Section 2 Dark</div>
<div class="sticky">Section 3 Light</div>
<div class="sticky">Section 4 Light</div>
<div class="sticky">Section 5 Light</div>
<div class="sticky dark">Section 6 Dark</div>
</main>
为了让菜单图标栏随着部分的上升或下降而变化,我们可以感知重叠的比率并使用适当的线性渐变设置 svg 填充颜色 - 具有三分之一、三分之二和完全填充的线性渐变。上面的代码片段设置了阈值,并开始使用线性渐变,但它并不完整 - 必须进行更多计算才能使 %s 正确。我希望在某个时候有时间回到这个问题上。
请注意,为了在具有不同纵横比的视口上进行此观察,导航的顶部填充已更改为相对值。
推荐阅读
- pdf - 使用 Acrobat Reader DC 打开 pdf 文件时出现“图像数据不足”
- javascript - 已解决 / React.js TypeError: Cannot read property '0' of undefined [Tic Tac Toe]
- python - 从查询字符串中提取熊猫数据框列名
- python - 根据文件名中的值合并 PDF
- javascript - Javascript:为 HTML 属性查找相应的元素和类型
- http - 所以我做了一个音乐机器人,但我不知道这是否是一个不和谐的错误
- sql - 如何编写一个在表中游标并插入到不同表中的 sql 脚本
- sql - 根据另一列数据选择列数据
- r - 将 2 行添加到 ggplot
- wordpress - 将 wordpress 实时数据提取到我的本地本地 laravel api