diff options
Diffstat (limited to 'src/lib/User')
| -rw-r--r-- | src/lib/User/BadgeWall/Badges.svelte | 28 | ||||
| -rw-r--r-- | src/lib/User/BadgeWall/badges.css | 9 |
2 files changed, 36 insertions, 1 deletions
diff --git a/src/lib/User/BadgeWall/Badges.svelte b/src/lib/User/BadgeWall/Badges.svelte index d2c56392..a77aebd6 100644 --- a/src/lib/User/BadgeWall/Badges.svelte +++ b/src/lib/User/BadgeWall/Badges.svelte @@ -1,4 +1,6 @@ <script lang="ts"> +import { onDestroy } from "svelte"; +import { browser } from "$app/environment"; import FallbackImage from "$lib/Image/FallbackImage.svelte"; import Spacer from "$lib/Layout/Spacer.svelte"; import LinkedTooltip from "$lib/Tooltip/LinkedTooltip.svelte"; @@ -16,6 +18,30 @@ export let categoryFilter: string | null; export let editMode: boolean; export let preferences: Preferences | undefined; export let selectedBadge: IndexedBadge | undefined = undefined; + +const skipObserver = + browser && typeof IntersectionObserver !== "undefined" + ? new IntersectionObserver( + (entries) => { + for (const entry of entries) + entry.target.classList.toggle( + "is-offscreen", + !entry.isIntersecting, + ); + }, + { rootMargin: "600px" }, + ) + : null; + +const skipWhenOffscreen = (node: HTMLElement) => { + skipObserver?.observe(node); + + return { + destroy: () => skipObserver?.unobserve(node), + }; +}; + +onDestroy(() => skipObserver?.disconnect()); </script> {#if ungroupedBadges.length === 0} @@ -42,7 +68,7 @@ export let selectedBadge: IndexedBadge | undefined = undefined; <div class="badges"> {#each badges as badge} - <div id={`badge-${badge.id}`}> + <div id={`badge-${badge.id}`} class="is-offscreen" use:skipWhenOffscreen> {#if editMode} <LinkedTooltip content={`${ diff --git a/src/lib/User/BadgeWall/badges.css b/src/lib/User/BadgeWall/badges.css index 19f8996f..f2e03988 100644 --- a/src/lib/User/BadgeWall/badges.css +++ b/src/lib/User/BadgeWall/badges.css @@ -11,6 +11,15 @@ gap: 0.25rem; } +/* Off-screen cells skip layout + paint. skipWhenOffscreen toggles this class + via IntersectionObserver so the containment — and the clipping it does to + the hover tilt, scale, and tooltip — is never active on an on-screen cell, + and the auto<->visible flip (which flashes) only ever happens off-screen. */ +.badges > .is-offscreen { + content-visibility: auto; + contain-intrinsic-size: auto 8rem; +} + .edit-row-2 { margin-top: -1.25rem; } |