From f6d611aec14eebb171fe92e90d524e1fa284f440 Mon Sep 17 00:00:00 2001 From: Artemii Peretiachenko Date: Thu, 24 Sep 2026 19:26:37 +0200 Subject: [PATCH] Keep the hero logo on screen while it scales down on scroll. The sticky stage was scrolling away, so the title clipped under the header and left an empty gap above the next section. Co-authored-by: Cursor --- common.js | 32 ++++++++++++++++++++++++++++++++ en/index.html | 4 ++-- en/terminal/index.html | 4 ++-- index.html | 4 ++-- src/index.html | 4 ++-- src/terminal.html | 4 ++-- styles.css | 36 +++++++++++++++++++++++++++++++++--- terminal/index.html | 4 ++-- ua/index.html | 4 ++-- ua/terminal/index.html | 4 ++-- 10 files changed, 81 insertions(+), 19 deletions(-) diff --git a/common.js b/common.js index 9ca7892..9882ad3 100644 --- a/common.js +++ b/common.js @@ -87,6 +87,23 @@ function initHeroScroll(config){ const siteHeader = document.querySelector('.site-header'); const mainNav = document.querySelector('.main-nav'); + let heroPin = null; + if (section && !section.parentElement?.classList.contains('hero-scroll')){ + const heroScroll = document.createElement('div'); + heroScroll.className = 'hero-scroll'; + section.parentElement.insertBefore(heroScroll, section); + heroScroll.appendChild(section); + } + if (section?.parentElement?.classList.contains('hero-scroll')){ + heroPin = section.parentElement.querySelector(':scope > .hero-pin'); + if (!heroPin){ + heroPin = document.createElement('div'); + heroPin.className = 'hero-pin'; + heroPin.setAttribute('aria-hidden', 'true'); + section.parentElement.appendChild(heroPin); + } + } + let cachedBaseHeight = 0; let cachedBrandGap = 32; let cachedMaxScale = 1.9; @@ -113,6 +130,7 @@ function initHeroScroll(config){ heroRoot.style.removeProperty('--hero-nav-shift-max'); heroRoot.style.removeProperty('--hero-scroll-start'); heroRoot.style.removeProperty('--hero-scroll-end'); + heroRoot.style.removeProperty('--hero-pin-space'); if (brandInner){ brandInner.style.removeProperty('animation-range'); brandInner.style.removeProperty('animation-timeline'); @@ -304,6 +322,19 @@ function initHeroScroll(config){ updateHeroBrand(); updateHeroContentLift(); + syncHeroPinSpace(); + } + + function syncHeroPinSpace(){ + if (!section || heroIsMobile || prefersReducedMotion || heroRunway <= 0){ + heroRoot.style.removeProperty('--hero-pin-space'); + return; + } + const runway = getHeroEffectiveRunway(); + const progress = runway > 0 ? Math.min(getHeroScrollProgress() / runway, 1) : 1; + const multiplier = getHeroScrollRunwayMultiplier(); + const spacer = heroRunway * Math.max(multiplier - 1, 0) * (1 - progress); + heroRoot.style.setProperty('--hero-pin-space', `${spacer}px`); } function updateHeroBrand(){ @@ -335,6 +366,7 @@ function initHeroScroll(config){ heroRoot.style.setProperty('--hero-scale', scale.toFixed(4)); heroRoot.style.setProperty('--hero-brand-height', `${brandHeight}px`); heroRoot.style.setProperty('--hero-stage-height', `${brandHeight + cachedNavHeight}px`); + syncHeroPinSpace(); } let heroScrollRaf = 0; diff --git a/en/index.html b/en/index.html index 34517ca..aa3e228 100644 --- a/en/index.html +++ b/en/index.html @@ -88,7 +88,7 @@ } })(); - + - + diff --git a/en/terminal/index.html b/en/terminal/index.html index f497c63..05d1d42 100644 --- a/en/terminal/index.html +++ b/en/terminal/index.html @@ -88,7 +88,7 @@ } })(); - + - + diff --git a/index.html b/index.html index 84e888e..4fb89f5 100644 --- a/index.html +++ b/index.html @@ -88,7 +88,7 @@ } })(); - + - + diff --git a/src/index.html b/src/index.html index f0ac792..2c33a3e 100644 --- a/src/index.html +++ b/src/index.html @@ -5,7 +5,7 @@ {{HEAD_META}} {{LANG_REDIRECT_SCRIPT}} - + - + diff --git a/src/terminal.html b/src/terminal.html index cac353a..9320c9f 100644 --- a/src/terminal.html +++ b/src/terminal.html @@ -5,7 +5,7 @@ {{HEAD_META}} {{LANG_REDIRECT_SCRIPT}} - + - + diff --git a/styles.css b/styles.css index a17481f..f576a89 100644 --- a/styles.css +++ b/styles.css @@ -45,7 +45,7 @@ body{ -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; transition: background var(--transition), color var(--transition); - overflow-x:hidden; + overflow-x:clip; } .ambient{ @@ -182,10 +182,37 @@ main, .site-footer{ --hero-max-scale:1.95; --hero-active-scale:var(--hero-max-scale); --hero-logo-size:clamp(60px, 11vw, 128px); - position:relative; + position:sticky; + top:var(--site-header-height); + z-index:2; padding-top:var(--hero-stage-offset); padding-bottom:var(--hero-bottom-gap); text-align:left; + background:var(--bg); +} +.hero-scroll{ + position:relative; + z-index:2; +} +.hero-pin{ + height:var(--hero-pin-space, 0px); +} +.hero-scroll + .post-hero-lift{ + position:relative; + z-index:1; + margin-top:calc(var(--hero-pin-space, 0px) * -1); +} +.hero::before, +.terminal-hero::before{ + content:''; + position:absolute; + z-index:-1; + left:50%; + top:0; + bottom:0; + width:100vw; + transform:translateX(-50%); + background:var(--bg); } .hero-stage{ position:sticky; @@ -697,11 +724,14 @@ main, .site-footer{ --hero-logo-size:clamp(72px, 13.5vw, 158px); --hero-terminal-overflow:1.14; --hero-brand-gap:var(--hero-bottom-gap); - position:relative; + position:sticky; + top:var(--site-header-height); + z-index:2; padding-top:var(--hero-stage-offset); padding-bottom:var(--hero-bottom-gap); text-align:center; overflow:visible; + background:var(--bg); } .terminal-stage{ position:sticky; diff --git a/terminal/index.html b/terminal/index.html index 275f96f..3a71ec7 100644 --- a/terminal/index.html +++ b/terminal/index.html @@ -88,7 +88,7 @@ } })(); - + - + diff --git a/ua/index.html b/ua/index.html index 9c139f9..2781ff3 100644 --- a/ua/index.html +++ b/ua/index.html @@ -88,7 +88,7 @@ } })(); - + - + diff --git a/ua/terminal/index.html b/ua/terminal/index.html index 70af7a8..95161d1 100644 --- a/ua/terminal/index.html +++ b/ua/terminal/index.html @@ -88,7 +88,7 @@ } })(); - + - +