hero.js: skriv aldri attributter på elementer appen hydrerer
lint-and-reload / lint (push) Successful in 2s
lint-and-reload / lint (push) Successful in 2s
Headerens høyde og teksten sin uttoning lå som inline-stiler på <header> og .hero-copy, satt før appen hydrerte; det kastet hydreringen av sporet (uhhm sin hero viser det samme), så ruteren aldri kom opp og hvert klikk ble en full sideinnlasting. Nå er de custom properties på <body>, som appen ikke hydrerer, og CSS-en leser dem. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 file changed
+22
-14
@@ -149,8 +149,13 @@ const CSS = `
|
|||||||
/* Sticky at the viewport top for the whole scroll (its containing
|
/* Sticky at the viewport top for the whole scroll (its containing
|
||||||
block is the page itself), z-index 0 so the cards (z-index 1)
|
block is the page itself), z-index 0 so the cards (z-index 1)
|
||||||
stack over it. The height is a floor, frozen to a measured pixel
|
stack over it. The height is a floor, frozen to a measured pixel
|
||||||
value by the module once it runs (see size()); the svh ladder is
|
value by the module once it runs (see size()) - as a custom
|
||||||
the first paint and the no-JS fallback. A floor and not a height,
|
property on <body>, never as an inline style on the header: the
|
||||||
|
module runs before the app hydrates, and an attribute written
|
||||||
|
onto an element the app is about to hydrate throws the hydration
|
||||||
|
off, and with it client-side navigation (uhhm's hero shows the
|
||||||
|
same). The svh ladder is the first paint and the no-JS fallback.
|
||||||
|
A floor and not a height,
|
||||||
so a copy that needs more than a screen (a phone) grows the header
|
so a copy that needs more than a screen (a phone) grows the header
|
||||||
rather than being clipped, and the cards start under it. */
|
rather than being clipped, and the cards start under it. */
|
||||||
position: sticky;
|
position: sticky;
|
||||||
@@ -160,6 +165,7 @@ const CSS = `
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
min-height: 100svh;
|
min-height: 100svh;
|
||||||
|
min-height: var(--westra-hero-h, 100svh);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -200,8 +206,11 @@ const CSS = `
|
|||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The copy's fade is a custom property too, for the same reason. */
|
||||||
.hero-module .hero-copy {
|
.hero-module .hero-copy {
|
||||||
position: static;
|
position: static;
|
||||||
|
opacity: var(--westra-copy, 1);
|
||||||
|
visibility: var(--westra-copy-vis, visible);
|
||||||
padding: 0 1.5rem 3.5rem;
|
padding: 0 1.5rem 3.5rem;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
text-shadow: 0 0.12em 1.4em var(--hero-glow);
|
text-shadow: 0 0.12em 1.4em var(--hero-glow);
|
||||||
@@ -325,7 +334,9 @@ class WestraHero {
|
|||||||
ensureStyle();
|
ensureStyle();
|
||||||
this.stopped = false;
|
this.stopped = false;
|
||||||
this.hero = container.closest('.hero') || container.parentElement;
|
this.hero = container.closest('.hero') || container.parentElement;
|
||||||
this.copy = this.hero ? this.hero.querySelector('.hero-copy') : null;
|
// Where the module's custom properties go: an element the app
|
||||||
|
// never hydrates, so writing to it cannot disturb hydration.
|
||||||
|
this.host = document.body;
|
||||||
this.reduced = window.matchMedia('(prefers-reduced-motion: reduce)');
|
this.reduced = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||||
this.dark = window.matchMedia('(prefers-color-scheme: dark)');
|
this.dark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
@@ -418,12 +429,11 @@ class WestraHero {
|
|||||||
const p = ease(this.progress);
|
const p = ease(this.progress);
|
||||||
this.name.style.setProperty('--p', p.toFixed(4));
|
this.name.style.setProperty('--p', p.toFixed(4));
|
||||||
// The copy goes sooner than the name: it has to be gone before
|
// The copy goes sooner than the name: it has to be gone before
|
||||||
// the first card reaches it, on a short screen too.
|
// the first card reaches it, on a short screen too. Written
|
||||||
if (this.copy) {
|
// on <body>, which the app does not hydrate (see the CSS).
|
||||||
const visible = 1 - clamp01(this.progress * 2.5);
|
const visible = 1 - clamp01(this.progress * 2.5);
|
||||||
this.copy.style.opacity = visible.toFixed(3);
|
this.host.style.setProperty('--westra-copy', visible.toFixed(3));
|
||||||
this.copy.style.visibility = visible <= 0.01 ? 'hidden' : '';
|
this.host.style.setProperty('--westra-copy-vis', visible <= 0.01 ? 'hidden' : 'visible');
|
||||||
}
|
|
||||||
|
|
||||||
this.draw(this.reduced.matches ? 0 : (now - this.t0) / 1000);
|
this.draw(this.reduced.matches ? 0 : (now - this.t0) / 1000);
|
||||||
|
|
||||||
@@ -446,7 +456,7 @@ class WestraHero {
|
|||||||
size() {
|
size() {
|
||||||
this.width = window.innerWidth;
|
this.width = window.innerWidth;
|
||||||
this.height = Math.max(1, window.innerHeight);
|
this.height = Math.max(1, window.innerHeight);
|
||||||
if (this.hero) this.hero.style.minHeight = this.height + 'px';
|
this.host.style.setProperty('--westra-hero-h', this.height + 'px');
|
||||||
this.fit();
|
this.fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,10 +593,8 @@ class WestraHero {
|
|||||||
const lose = this.gl.getExtension('WEBGL_lose_context');
|
const lose = this.gl.getExtension('WEBGL_lose_context');
|
||||||
if (lose) lose.loseContext();
|
if (lose) lose.loseContext();
|
||||||
}
|
}
|
||||||
if (this.hero) this.hero.style.minHeight = '';
|
for (const prop of ['--westra-hero-h', '--westra-copy', '--westra-copy-vis']) {
|
||||||
if (this.copy) {
|
this.host.style.removeProperty(prop);
|
||||||
this.copy.style.opacity = '';
|
|
||||||
this.copy.style.visibility = '';
|
|
||||||
}
|
}
|
||||||
this.canvas.remove();
|
this.canvas.remove();
|
||||||
this.name.remove();
|
this.name.remove();
|
||||||
|
|||||||
Reference in new issue
Block a user