artist page: end the pane's scroll at the content (clip the 300vh sheet out of the scroll range)
The pane could scroll ~850px (1971px at a tall window) past the last content pixel: at max scroll ZERO of 11 release rows were on screen, the whole viewport empty page. The sheet is 300vh of absolutely positioned decoration, and an abs-positioned descendant extends its scroller's scrollable overflow. .content's scrollHeight tracked the sheet's box — pin flow origin + the sheet's live translate + 300vh — instead of the page. Because that translate is scroll-driven, the range also breathed with scroll position and depended on scroll history: the same scrollTop measured 4167, 4329 and 4368 depending on the route taken. Hiding the sheet gave exactly 1797, the page plus the pane's padding-top. Wrap the sheet in a .sheetclip box with overflow: clip, sized to the pane's client box, so the sheet paints exactly the region the pane can show and contributes nothing to the scroll range. - The clip box is ABSOLUTE and the pin stays height: 0. Sizing the pin itself and cancelling with a negative margin-bottom leaves +24px behind — the margin collapses against the neighbouring height-0 pins and walks the hero zone from 24 to 48. Out of flow there is no margin to collapse, and the sticky constraint is untouched. - overflow-clip-margin is not an option for the sheet's 28px bleed: it re-expands the overflow region right back to 2440. The bleed moves onto the clip box instead. - The sheet's offsets are now clip-box relative. --band-from-pin is pin-relative and the box sits --pin-origin above the pin, so the two cancel: --band-from-pin + --pin-origin is --band-top. - --frame-h (measure()'s scroller.clientHeight) becomes unconditional. It fed the scroll-driven-only .fade-frame; .sheetclip needs it on both branches. Setting it on the fallback path is inert — .fade-frame's rule lives inside the @supports block and never matches there. Verified live against the pre-change rendering at identical scrollTop, each comparison bracketed by two baseline captures so the hero's 20s rotation could not be mistaken for a difference: 0 differing pixels at four of five stops (the fifth is one chip's hover ring, 83px), hero zone and scrollbody unmoved at every stop. Scroll range is now content-exact with the clip box flush to the pane at 1280x800, 1600x1100, 1100x620 and 1920x1400, and across artists with 4, 10, 11 and 22 rows. At max scroll all 11 rows are on screen instead of none.
This commit is contained in:
1 parent
2eb1cf57e3
commit
0878659f6a
1 file changed
+51
-5
@@ -1166,8 +1166,13 @@
|
||||
const hostFlowTop = zone.offsetTop + zone.offsetHeight - 18;
|
||||
const fadeS = Math.max(0, hostFlowTop - cutScreen);
|
||||
page.style.setProperty("--fade-s", `${fadeS.toFixed(1)}px`);
|
||||
page.style.setProperty("--frame-h", `${scroller.clientHeight}px`);
|
||||
}
|
||||
// Unconditional: .fade-frame is scroll-driven-only, but .sheetclip
|
||||
// sizes itself from --frame-h on BOTH branches (it is what keeps the
|
||||
// 300vh sheet out of the pane's scroll range). Setting it on the
|
||||
// fallback path is otherwise inert — .fade-frame's rule lives inside
|
||||
// the @supports block and never matches there.
|
||||
page.style.setProperty("--frame-h", `${scroller.clientHeight}px`);
|
||||
// The extras' hit-gate sentinel parks at the scrollTop where
|
||||
// p crosses 0.42. Probed live (2026-07-24, this WebView2): the
|
||||
// observers' rootBounds top coincides with the page's box top
|
||||
@@ -3409,7 +3414,9 @@
|
||||
the wash of rounds 7-10: fewer layers, nothing to hand over
|
||||
between them, and a baked gradient moved as a whole cannot
|
||||
seam. -->
|
||||
<div class="sheetpin" aria-hidden="true"><div class="sheet"></div></div>
|
||||
<div class="sheetpin" aria-hidden="true">
|
||||
<div class="sheetclip"><div class="sheet"></div></div>
|
||||
</div>
|
||||
|
||||
<!-- LAYER 30 — THE IDENTITY. The block's bottom IS --edge at every
|
||||
scroll position, so the wordmark and the Play/chips row are
|
||||
@@ -4084,13 +4091,52 @@
|
||||
seams of rounds 7-10 all came from recomputing stops against the
|
||||
scroll. This one element replaces the scrim, the veil, the eraser and
|
||||
the wash. */
|
||||
.sheet {
|
||||
/* THE SHEET'S CLIP BOX — the reason the pane's scroll range equals its
|
||||
content. The sheet is 300vh of absolutely-positioned decoration, and an
|
||||
abs-positioned descendant extends its scroller's SCROLLABLE OVERFLOW:
|
||||
measured, .content's scrollHeight tracked the sheet's box (pin flow
|
||||
origin + the sheet's live translate + 300vh) instead of the page, so the
|
||||
pane scrolled ~850px past the last content pixel — at max scroll ZERO of
|
||||
11 release rows were on screen, the whole viewport empty page. Worse, the
|
||||
sheet's translate is scroll-driven, so the range BREATHED with scroll
|
||||
position and depended on scroll history (same scrollTop measured 4167,
|
||||
4329 and 4368 by route; hidden .sheet gave exactly 1797 = content).
|
||||
`overflow: clip` here stops that propagation at the clip box's own
|
||||
geometry — the region the pane can actually show — so the sheet paints
|
||||
identically and contributes nothing.
|
||||
ABSOLUTE, and the pin stays height:0: sizing the PIN itself and cancelling
|
||||
with margin-bottom:-100% leaves +24px behind (the negative margin
|
||||
collapses against the neighbouring height-0 pins and walks the hero zone
|
||||
24 → 48). Out of flow, there is no margin to collapse and the sticky
|
||||
constraint is untouched.
|
||||
The box IS the pane's client box: --pin-origin up to undo the pane's
|
||||
padding-top (the pins stick that far below the pane's visible top), and
|
||||
one pane tall. --frame-h is measure()'s scroller.clientHeight; the 100vh
|
||||
fallback only covers the pre-measure first paint, where a too-tall clip
|
||||
is harmless (it just clips less). */
|
||||
.sheetclip {
|
||||
position: absolute;
|
||||
top: var(--band-from-pin);
|
||||
top: calc(-1 * var(--pin-origin));
|
||||
/* The sheet's full-bleed lives here now — the clip edge has to sit on
|
||||
the pane's padding edge, or it would shave the bleed off instead. */
|
||||
left: -28px;
|
||||
right: -28px;
|
||||
height: var(--frame-h, 100vh);
|
||||
overflow: clip;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sheet {
|
||||
position: absolute;
|
||||
/* In clip-box coordinates. --band-from-pin is pin-relative and the box
|
||||
sits --pin-origin above the pin, so the two terms cancel to the
|
||||
band's own offset: --band-from-pin + --pin-origin ≡ --band-top. */
|
||||
top: var(--band-top);
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* Far past any scrollport bottom; the gradient's tail is opaque page
|
||||
colour, so extra height is just more page. */
|
||||
colour, so extra height is just more page. Free now — the clip box
|
||||
keeps it out of the scrollable overflow however tall it is. */
|
||||
height: 300vh;
|
||||
pointer-events: none;
|
||||
/* The glide is EASED (p²), not linear — the user could see the
|
||||
|
||||
Reference in new issue
Block a user