admin管理员组

文章数量:1122846

When modifying the height of a sticky header based on a threshold for the yScroll position, the animation can loop infinitely if scrolling is stopped close to the threshold, as the shrinking header itself reduces the value of yScroll and thereby triggers it to grow again (and so on). I fixed the problem by triggering the animation only if the threshold was crossed including a buffer value.

While the code below works fine, I could not find a way to use $derived instead of $effect. Is this problem solvable using $derived? Am I approaching the issue correctly?

<script lang="ts">
    let yScroll = $state(0);
    let threshold = 50;
    let buffer = 40;
    let isShrunk = $state(false);

    $effect(() => {
        if (yScroll >= threshold + buffer) {
            isShrunk = true;
        } else if (yScroll <= threshold - buffer) {
            isShrunk = false;
        }
    });
</script>

<svelte:window bind:scrollY={yScroll} />

<header class="transition-all duration-500 {isShrunk ? 'h-16' : 'h-32'}">Header</header>

When modifying the height of a sticky header based on a threshold for the yScroll position, the animation can loop infinitely if scrolling is stopped close to the threshold, as the shrinking header itself reduces the value of yScroll and thereby triggers it to grow again (and so on). I fixed the problem by triggering the animation only if the threshold was crossed including a buffer value.

While the code below works fine, I could not find a way to use $derived instead of $effect. Is this problem solvable using $derived? Am I approaching the issue correctly?

<script lang="ts">
    let yScroll = $state(0);
    let threshold = 50;
    let buffer = 40;
    let isShrunk = $state(false);

    $effect(() => {
        if (yScroll >= threshold + buffer) {
            isShrunk = true;
        } else if (yScroll <= threshold - buffer) {
            isShrunk = false;
        }
    });
</script>

<svelte:window bind:scrollY={yScroll} />

<header class="transition-all duration-500 {isShrunk ? 'h-16' : 'h-32'}">Header</header>
Share Improve this question edited Nov 25, 2024 at 22:16 Philipp asked Nov 22, 2024 at 14:13 PhilippPhilipp 424 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

This feels very event-based, so I don't think $derived is the right tool.

If you describe what was happening before the logic change and after, this should become more apparent:

Before: "Header is shrunk while scroll offset is smaller than threshold"
After: "Header is shrunk when scroll offset crosses upper boundary and expanded when scroll offset crosses lower boundary.

The former describes a consistent condition, the latter two discrete events that have to be detected.

If you don't like the $effect (which I would say is fine here), you could also use the scroll event instead.

<svelte:window on:scroll={onScroll} />
function onScroll() {
    if (window.scrollY >= threshold + buffer) {
        isShrunk = true;
    } else if (window.scrollY <= threshold - buffer) {
        isShrunk = false;
    }
}

Though the function might need to be called once, if the initial state is off.

本文标签: css animationsUse derived based on current state of selfStack Overflow