You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte crossfade 为何使元素位移而非原地交叉淡入淡出?

问题描述

尝试基于布尔值实现两个元素的交叉淡入淡出效果,但实际运行时两个元素并未在同一位置切换,而是出现垂直位移,希望它们保持固定位置完成过渡。

代码示例
<script lang="ts">
  import { crossfade } from "svelte/transition";

  const [send, receive] = crossfade({
    duration: 1500,
  });

  let foo = true;

  function handleClick() {
        foo=!foo;
    }
</script>

<h1>My example</h1>
<button on:click={handleClick}>Click me {foo}</button>
<div>
  {#if foo}
    <div in:send={{ key: "a" }} out:receive={{ key: "a" }}>
      one
    </div>
  {:else}
    <div in:send={{ key: "a" }} out:receive={{ key: "a" }}>
      two
    </div>
  {/if}
</div>
解决方案

出现垂直位移的核心原因是crossfade过渡会将元素设置为绝对定位,但包裹元素的父容器未设置相对定位,导致过渡元素相对于整个页面定位,而非父容器。只需给包裹两个元素的<div>添加相对定位样式,同时确保过渡期间父容器高度稳定即可解决:

修改后的代码如下:

<script lang="ts">
  import { crossfade } from "svelte/transition";

  const [send, receive] = crossfade({
    duration: 1500,
  });

  let foo = true;

  function handleClick() {
        foo=!foo;
    }
</script>

<h1>My example</h1>
<button on:click={handleClick}>Click me {foo}</button>
<!-- 添加相对定位和最小高度,确保容器尺寸稳定 -->
<div style="position: relative; min-height: 1.5em;">
  {#if foo}
    <div in:send={{ key: "a" }} out:receive={{ key: "a" }}>
      one
    </div>
  {:else}
    <div in:send={{ key: "a" }} out:receive={{ key: "a" }}>
      two
    </div>
  {/if}
</div>

关键设置说明:

  • position: relative:让过渡元素的绝对定位相对于这个父容器,保证两个元素在同一位置切换。
  • min-height: 1.5em:防止父容器在元素过渡时高度塌陷,避免页面布局抖动。

如果两个元素高度差异较大,还可以给每个过渡元素设置固定高度,或者让父容器取最大元素的高度,进一步确保过渡期间容器尺寸一致。

内容的提问来源于stack exchange,提问作者shainanigans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:07:24