Check Section Theme on Scroll
Watches the scroll position against a navbar-height offset and updates data-theme-nav and data-bg-nav on the body as the user scrolls through sections tagged with data-theme-section and data-bg-section. Drive nav colour and background with pure CSS attribute selectors.
Code
<body data-theme-nav="light" data-bg-nav="light">
<nav data-nav-bar-height></nav>
<section class="section-header" data-theme-section="dark" data-bg-section="blue"></section>
<section class="section-work" data-theme-section="dark" data-bg-section="orange"></section>
<section class="section-about" data-theme-section="light" data-bg-section="yellow"></section>
<section class="section-contact" data-theme-section="light" data-bg-section="light"></section>
</body>/* Nav Theme */
[data-theme-nav="light"] .nav__inner {
color: #131313;
}
[data-theme-nav="dark"] .nav__inner {
color: #EFEEEC;
}
/* Nav Background */
[data-bg-nav="pink"] .nav__inner {
background-color: #562041;
}
[data-bg-nav="black"] .nav__inner {
background-color: #1F1F1F;
}
[data-bg-nav="lightblue"] .nav__inner {
background-color: #204b63;
}
[data-bg-nav="darkgreen"] .nav__inner {
background-color: #C9FC7D;
}function initCheckSectionThemeScroll() {
// Get detection offset, in this case the navbar
const navBarHeight = document.querySelector("[data-nav-bar-height]");
const themeObserverOffset = navBarHeight ? navBarHeight.offsetHeight / 2 : 0;
function checkThemeSection() {
const themeSections = document.querySelectorAll("[data-theme-section]");
themeSections.forEach(function(themeSection) {
const rect = themeSection.getBoundingClientRect();
const themeSectionTop = rect.top;
const themeSectionBottom = rect.bottom;
// If the offset is between the top & bottom of the current section
if (themeSectionTop <= themeObserverOffset && themeSectionBottom >= themeObserverOffset) {
// Check [data-theme-section]
const themeSectionActive = themeSection.getAttribute("data-theme-section");
document.querySelectorAll("[data-theme-nav]").forEach(function(elem) {
if (elem.getAttribute("data-theme-nav") !== themeSectionActive) {
elem.setAttribute("data-theme-nav", themeSectionActive);
}
});
// Check [data-bg-section]
const bgSectionActive = themeSection.getAttribute("data-bg-section");
document.querySelectorAll("[data-bg-nav]").forEach(function(elem) {
if (elem.getAttribute("data-bg-nav") !== bgSectionActive) {
elem.setAttribute("data-bg-nav", bgSectionActive);
}
});
}
});
}
function startThemeCheck() {
document.addEventListener("scroll", checkThemeSection);
}
// Initial check and start listening for scroll
checkThemeSection();
startThemeCheck();
}
// Initialize Check Section Theme on Scroll
document.addEventListener('DOMContentLoaded', () => {
initCheckSectionThemeScroll();
});Guide
How It Works
On every scroll event, the script measures the vertical midpoint of the navbar (data-nav-bar-height) and checks which section contains that point. It then updates data-theme-nav and data-bg-nav on matching elements (typically the body) to reflect the active section's values.
data-theme-nav & data-bg-nav
Add both to the <body> (or any persistent element like the nav). These are the attributes that change as the user scrolls, and which your CSS listens to in order to apply the correct nav styles.
data-theme-section & data-bg-section
Add to each <section> that should influence the nav. Set data-theme-section to a theme name (e.g. "light" or "dark") and data-bg-section to a background identifier (e.g. "blue", "orange"). The values are arbitrary — they just need to match your CSS selectors.
data-nav-bar-height
Add to the navbar element. The script reads its offsetHeight and uses half of that as the detection threshold — the point in the viewport where a section is considered "active". If omitted, the threshold falls back to 0 (the very top of the viewport).
Animating
Target [data-theme-nav] and [data-bg-nav] in CSS with attribute selectors to change nav colours, backgrounds, or any other property. Add CSS transitions to the nav's inner element for smooth changes between sections.