Skip to content

Commit e59bede

Browse files
interacseanclaude
andcommitted
fix: make scroll-fade seamless via content mask, not a colour overlay
The page backdrop is a theme gradient with background-attachment: fixed, so no single overlay colour (--background or --shell-gradient-base) could match it — hence the persistent darker band. Replace the colour overlay with a mask-image on the content that fades its top edge to transparent when scrolled, revealing the real backdrop underneath. Seamless on every theme by construction; applied only when scrolled so content isn't faded at rest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4ce8d77 commit e59bede

1 file changed

Lines changed: 9 additions & 20 deletions

File tree

packages/core/src/components/sidebar/sidebar-layout.tsx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,35 +112,24 @@ export const SidebarLayout = (props: SidebarLayoutProps) => {
112112
margin / padding pair mirrors SidebarInset's own responsive
113113
padding (px-4, → px-8 at md when the sidebar is the inset
114114
variant). */}
115+
{/* Scroll-fade: once scrolled, a mask fades the top edge of the
116+
content to transparent so it dissolves into the pinned breadcrumb
117+
rather than cutting off. Masking (rather than overlaying a matching
118+
colour) reveals the real page backdrop — which is a theme gradient
119+
with `background-attachment: fixed`, so no single colour could
120+
match it — making the fade seamless on every theme. Only applied
121+
when scrolled, so content isn't faded at rest. */}
115122
<div
116123
ref={scrollRef}
117124
onScroll={handleScroll}
118125
data-scrolled={scrolled ? "" : undefined}
119126
className={cn(
120-
"astw:group/scroll astw:flex astw:flex-col astw:gap-4 astw:flex-1 astw:min-h-0 astw:overflow-y-auto",
127+
"astw:flex astw:flex-col astw:gap-4 astw:flex-1 astw:min-h-0 astw:overflow-y-auto",
121128
"astw:-mr-4 astw:pr-4",
122129
"astw:md:group-has-data-[variant=inset]/sidebar-wrapper:-mr-8 astw:md:group-has-data-[variant=inset]/sidebar-wrapper:pr-8",
130+
"astw:data-[scrolled]:[mask-image:linear-gradient(to_bottom,transparent,black_2rem)]",
123131
)}
124132
>
125-
{/* Scroll-fade: a sticky strip that rides the top of the scroll
126-
viewport so content dissolves into the pinned breadcrumb rather
127-
than cutting off. It's a seamless gradient from the page
128-
backdrop colour (--shell-gradient-base, which themes with a
129-
gradient page background anchor to; falls back to --background)
130-
at full opacity to the SAME colour at zero alpha — using
131-
relative-colour syntax rather than `transparent` (which is
132-
black·0 and would band to grey on light themes). h-8 with -mb-12
133-
cancels its own height plus the flex gap so it adds no layout
134-
space; it fades in once scrolled and is inert to pointer
135-
events. */}
136-
<div
137-
aria-hidden
138-
style={{
139-
backgroundImage:
140-
"linear-gradient(to bottom, var(--shell-gradient-base, var(--background)), rgb(from var(--shell-gradient-base, var(--background)) r g b / 0))",
141-
}}
142-
className="astw:pointer-events-none astw:sticky astw:top-0 astw:z-10 astw:-mb-12 astw:h-8 astw:shrink-0 astw:opacity-0 astw:transition-opacity astw:duration-200 astw:group-data-[scrolled]/scroll:opacity-100"
143-
/>
144133
{Children ?? <AppShellOutlet />}
145134
</div>
146135
</SidebarInset>

0 commit comments

Comments
 (0)