.
However, some themes and Elementor defer template rendering, so
the header HTML (Snippet 2, injected at wp_body_open) may not be
fully parsed yet when this script first evaluates.
Wrapping inside init() called via DOMContentLoaded guarantees
every getElementById / querySelector finds its element.WHY NO SINGLE EARLY-RETURN GUARD:
The old code had `if (!header) return` which exited the ENTIRE
script if even one element was missing — killing the scroll
handler, the overlay, the hamburger, and the offset all at once.
Each section below has its OWN null check so the rest of the
script always runs regardless.
---------------------------------------------------------------- */
function init() {/* ----------------------------------------------------------
ELEMENT REFERENCES (re-queried inside init so they are
always fresh after DOMContentLoaded)
---------------------------------------------------------- */
var header = document.getElementById('ee-header');
var hamburger = document.getElementById('ee-hamburger');
var mobileNav = document.getElementById('ee-mobile-nav');
var overlay = document.getElementById('ee-services-overlay');
var overlayClose = document.getElementById('ee-overlay-close');
var overlayBackdrop = document.getElementById('ee-overlay-backdrop');
var servicesBtns = document.querySelectorAll('#ee-services-btn, #ee-services-mobile-btn');
var overlayTimer = null;/* ----------------------------------------------------------
1. DYNAMIC CONTENT OFFSET + CSS VARIABLE
Applies to EVERY page (including home page).Home page: content is pushed down by header height, AND
the CSS rule `.home .elementor-section-wrap > :first-child`
uses margin-top: calc(-1 * var(--ee-hh)) to pull the hero's
background back up behind the transparent header.Inner pages: content is simply pushed below the header.--ee-hh is a CSS variable so the home-page hero rule in
Snippet 1 always matches the real rendered header height,
even after a resize at a different breakpoint.
---------------------------------------------------------- */
function applyContentOffset() {
var wrapper = document.getElementById('ee-header-wrapper');
if (!wrapper) return;var h = wrapper.offsetHeight; /* real px height: ticker + nav bar *//* Publish to CSS so Snippet 1 home-hero rule can use it */
document.documentElement.style.setProperty('--ee-hh', h + 'px');/* Find the Elementor / WordPress content container to push down.
Selectors tried in priority order: most specific first. */
var selectors = [
'.elementor-page-wrapper',
'.elementor-section-wrap',
'#main',
'main#main',
'.site-main',
'#content',
'#page'
];var target = null;
for (var i = 0; i < selectors.length; i++) {
target = document.querySelector(selectors[i]);
if (target) break;
}if (target) {
target.style.paddingTop = h + 'px';
}
}applyContentOffset();
window.addEventListener('resize', applyContentOffset, { passive: true });/* ----------------------------------------------------------
2. SCROLL HANDLER — transparent → solid
Uses background-color (NOT background shorthand) to match
the livingwithpixels tutorial exactly.
Only runs if #ee-header was found.
---------------------------------------------------------- */
if (header) {
function handleScroll() {
if (window.pageYOffset > 50) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
}window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll(); /* run immediately — handles mid-page load */
}/* ----------------------------------------------------------
3. MOBILE NAV PANEL (hamburger toggle)
Null-checked independently — won't affect scroll or overlay.
---------------------------------------------------------- */
function setMobileNav(open) {
if (!hamburger || !mobileNav) return;
hamburger.classList.toggle('open', open);
mobileNav.classList.toggle('open', open);
hamburger.setAttribute('aria-expanded', open ? 'true' : 'false');
hamburger.setAttribute('aria-label',
open ? 'Close Navigation Menu' : 'Open Navigation Menu');
mobileNav.setAttribute('aria-hidden', open ? 'false' : 'true');
document.body.style.overflow = open ? 'hidden' : '';
}if (hamburger && mobileNav) {
hamburger.addEventListener('click', function () {
setMobileNav(!mobileNav.classList.contains('open'));
});
}/* ----------------------------------------------------------
4. SERVICES FULL-SCREEN OVERLAY
open → backdrop fades in, content slides from left (desktop)
/ right (mobile) — matches JSON entrance animations
close → content slides out to right, backdrop fades out
Null-checked independently from everything else.
---------------------------------------------------------- */
function openOverlay() {
if (!overlay) return;if (overlayTimer) {
clearTimeout(overlayTimer);
overlayTimer = null;
overlay.classList.remove('closing');
}overlay.classList.add('open');
overlay.setAttribute('aria-hidden', 'false');/* Close mobile nav if it happens to be open */
if (mobileNav && mobileNav.classList.contains('open')) {
setMobileNav(false);
}document.body.style.overflow = 'hidden';servicesBtns.forEach(function (btn) {
btn.setAttribute('aria-expanded', 'true');
});/* Defer focus so CSS transition doesn't interrupt it */
if (overlayClose) {
setTimeout(function () { overlayClose.focus(); }, 120);
}
}function closeOverlay() {
if (!overlay) return;overlay.classList.add('closing');
overlay.setAttribute('aria-hidden', 'true');servicesBtns.forEach(function (btn) {
btn.setAttribute('aria-expanded', 'false');
});/* Remove classes after CSS exit transition finishes (420ms) */
overlayTimer = setTimeout(function () {
overlay.classList.remove('open', 'closing');
document.body.style.overflow = '';
overlayTimer = null;
}, 420);
}/* Click on any Services trigger (desktop + mobile nav) */
servicesBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
if (overlay && overlay.classList.contains('open')) {
closeOverlay();
} else {
openOverlay();
}
});
});/* Close by clicking the dark backdrop */
if (overlayBackdrop) {
overlayBackdrop.addEventListener('click', closeOverlay);
}/* Close by clicking the × button */
if (overlayClose) {
overlayClose.addEventListener('click', closeOverlay);
}/* ----------------------------------------------------------
5. KEYBOARD: Escape closes overlay or mobile nav
---------------------------------------------------------- */
document.addEventListener('keydown', function (e) {
var key = e.key || e.keyCode;
if (key === 'Escape' || key === 'Esc' || key === 27) {
if (overlay && overlay.classList.contains('open')) {
closeOverlay();
var trigger = document.getElementById('ee-services-btn');
if (trigger) trigger.focus();
} else if (mobileNav && mobileNav.classList.contains('open')) {
setMobileNav(false);
if (hamburger) hamburger.focus();
}
}
});/* ----------------------------------------------------------
6. FOCUS TRAP inside overlay (accessibility)
Keeps Tab cycling within the overlay while it's open.
---------------------------------------------------------- */
if (overlay) {
overlay.addEventListener('keydown', function (e) {
if (!overlay.classList.contains('open')) return;
if (e.key !== 'Tab' && e.keyCode !== 9) return;var focusable = overlay.querySelectorAll(
'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
var first = focusable[0];
var last = focusable[focusable.length - 1];if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
}} /* end init() *//* ----------------------------------------------------------------
CALL INIT: run after DOM is parsed so all elements exist.
If readyState is already 'interactive' or 'complete' (common in
footer scripts), call init() immediately.
---------------------------------------------------------------- */
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}})();
Elevate Your Website’s Rankings: Schedule a Professional SEO Audit to Uncover Hidden Opportunities and Drive Growth. ✦ Transform Your Online Strategy: Book a Personalized SEO Consultation to Achieve Dominance in Global Search Results. ✦
Elevate Your Website’s Rankings: Schedule a Professional SEO Audit to Uncover Hidden Opportunities and Drive Growth. ✦ Transform Your Online Strategy: Book a Personalized SEO Consultation to Achieve Dominance in Global Search Results. ✦
WordPress web design services refer to custom design work that creates an attractive and easy-to-use website on the WordPress platform. It’s a blend of custom visual design with the functionality and content management features of WordPress software. In this in-depth article, we’ll explain WordPress design services for professionals, DIYers, pricing, process, and best practices based on our […]