fix: anchor scroll — double-rAF timing + scroll-mt-20 on match cards
useEffect fired before the browser had laid out the freshly-rendered match cards, so getElementById returned null or scrollIntoView ran before the element was in its final position. Double requestAnimationFrame waits for React's commit AND the browser's layout pass. scroll-mt-20 (80 px) adds clearance for the 60 px sticky nav so the targeted card isn't hidden beneath it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -76,8 +76,11 @@ export function TournamentClient({ params }: { params: Promise<{ year: string }>
|
|||||||
if (!data) return
|
if (!data) return
|
||||||
const hash = window.location.hash
|
const hash = window.location.hash
|
||||||
if (!hash) return
|
if (!hash) return
|
||||||
const el = document.getElementById(hash.slice(1))
|
// double-rAF: first frame commits React's DOM, second frame lets the browser lay out
|
||||||
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||||
|
const el = document.getElementById(hash.slice(1))
|
||||||
|
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||||
|
}))
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
|
|
||||||
@@ -162,7 +165,7 @@ export function TournamentClient({ params }: { params: Promise<{ year: string }>
|
|||||||
<h2 className="font-['Bebas_Neue'] text-2xl text-green-light mb-4">LIVE</h2>
|
<h2 className="font-['Bebas_Neue'] text-2xl text-green-light mb-4">LIVE</h2>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{liveMatches.map(m => (
|
{liveMatches.map(m => (
|
||||||
<div key={m.id} id={`match-${m.id}`}>
|
<div key={m.id} id={`match-${m.id}`} className="scroll-mt-20">
|
||||||
<MatchCard match={m} />
|
<MatchCard match={m} />
|
||||||
<GoalList match={m} />
|
<GoalList match={m} />
|
||||||
</div>
|
</div>
|
||||||
@@ -205,7 +208,7 @@ export function TournamentClient({ params }: { params: Promise<{ year: string }>
|
|||||||
{/* Group matches */}
|
{/* Group matches */}
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{groupMatches.map(m => (
|
{groupMatches.map(m => (
|
||||||
<div key={m.id} id={`match-${m.id}`}>
|
<div key={m.id} id={`match-${m.id}`} className="scroll-mt-20">
|
||||||
<MatchCard match={m} compact />
|
<MatchCard match={m} compact />
|
||||||
<GoalList match={m} />
|
<GoalList match={m} />
|
||||||
</div>
|
</div>
|
||||||
@@ -226,7 +229,7 @@ export function TournamentClient({ params }: { params: Promise<{ year: string }>
|
|||||||
<h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{round}</h3>
|
<h3 className="text-[13px] font-bold text-green tracking-wide uppercase mb-3">{round}</h3>
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{roundMatches.map(m => (
|
{roundMatches.map(m => (
|
||||||
<div key={m.id} id={`match-${m.id}`}>
|
<div key={m.id} id={`match-${m.id}`} className="scroll-mt-20">
|
||||||
<MatchCard match={m} compact />
|
<MatchCard match={m} compact />
|
||||||
<GoalList match={m} />
|
<GoalList match={m} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user