Skip to content

Equivalent of Vue's out-in transition mode #544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Rich-Harris opened this issue May 1, 2017 · 16 comments
Open

Equivalent of Vue's out-in transition mode #544

Rich-Harris opened this issue May 1, 2017 · 16 comments

Comments

@Rich-Harris
Copy link
Member

For elements that are positioned statically or relatively, intros that happen at the same time as outros can be problematic:

{{#if foo}}
  <div transition:fade='{duration:1500}'>yep</div>
{{else}}
  <div transition:fade='{duration:1500}'>nope</div>
{{/if}}

yep-nope

Vue has a nice solution to this — transition modes. Since Svelte doesn't have an equivalent of <transition>, the concept doesn't translate directly, but it would be nice to be able to express something similar without the hacky use of delay.

@aubergene
Copy link

Just my 2¢ but this seems too fancy too me, just let people do whatever with CSS. The Vue docs demo of in-out doesn't even appear to work smoothly without a jump for me in Firefox 57

@antony
Copy link
Member

antony commented Feb 14, 2020

I'm not 100% sure that the current behaviour feels like a hack:

https://svelte.dev/repl/07465934948446f2b1fe823731225c57?version=3.18.2

Seems fairly reasonable to me. Unless there is specific appetite for improving transitions further?

@Blazzike
Copy link

https://svelte.dev/repl/96ade4f9af6c4bb59dc2ea23c43f72f2?version=3.18.2

@antony this is the problem with that method.

@braebo
Copy link
Member

braebo commented Sep 6, 2020

I encounter this problem in all of my Svelte projects- feels like I'm missing something. Fighting it with absolute positioning usually forces me to re-write a lot of CSS multiple times.

Is there is a better way to solve this that I've overlooked? Or would it be better to use an external animation library for animation-heavy projects?

+1 to the appetite for further improving transitions 😁

@TylerRick
Copy link

What do you think of the workaround (position: "absolute") mentioned here?

@stale
Copy link

stale bot commented Jun 26, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@pngwn
Copy link
Member

pngwn commented Jul 11, 2021

I think this is still a valid feature not worthy of an RFC. Reopening.

@pngwn pngwn reopened this Jul 11, 2021
@SohumB
Copy link

SohumB commented Sep 7, 2021

For anyone else finding this issue, the linked stackoverflow also now suggests a workaround that uses css-grid, and doesn't require the machinery the previous workaround did. It boils down to adding a div around the transitioning element that needs to share space with a different copy of it, and styling it like this:

.transition-enforcement {
  display: grid;
}

.transition-enforcement > * {
  grid-column: 1/2;
  grid-row: 1/2;
}

@gyurielf
Copy link

It's still would be very nice to have.

@bfanger
Copy link
Contributor

bfanger commented Jan 8, 2022

I've written an outin.ts utility which like crossfade creates out and in functions:

  • The :out transition starts immediately
  • Automaticly calculates the delay of the in:
  • Minimize layout shift by setting out: node to position: absolute
  • Abortable & Undoable (Reversed transitions)

REPL

<script>
import { fade } from "svelte/transition";
import outin from "$lib/outin";

const [fadeOut, fadeIn] = outin({ transition: fade });

let foo = true
</script>

{{#if foo}}
  <div in:fadeIn out:fadeOut>yep</div>
{{else}}
  <div in:fadeIn out:fadeOut>nope</div>
{{/if}}

To add duration in the template:
<div in:fadeIn={{duration: 1500}} in:fadeIn={{duration: 1500}} />
or in the script:
outin({ transition: (node, options = {}) => fade(node, { duration: 1500, ...options })});

const [blurOut, flyIn] = outin({ out: blur, in: fly });

I think it's a nice starting point and could serve as inspiration for something we could import from svelte/transtion

@craxrev
Copy link

craxrev commented Jan 21, 2022

I like the utility above but I don't know if it's a bug or not, I still have the layout shift but only when switching back to an element which is higher in the stacking context than the current element, for example:

{{#if foo}}
  <div in:fadeIn out:fadeOut>yep</div>
{{else}}
  <div in:fadeIn out:fadeOut>nope</div>
{{/if}}
  • yep to nope: crossfades smoothly
  • nope to yep: crossfades with layout shift

But in my case I have a loop with a condition inside it, maybe that causes a problem..

I ended up using the grid solution as proposed by @SohumB:

<div class="transition-enforcement">
  {#each slides as slide, id}
    {#if cur === id}
      <div in:fade out:fade>
        <h4>{slide.name}</h4>
        <h5>{slide.title}</h5>
        <p>{slide.quote}</p>
      </div>
    {/if}
  {/each}
</div>
<style>
.transition-enforcement {
  display: grid;
}
.transition-enforcement > * {
  grid-column: 1/2;
  grid-row: 1/2;
}
</style>

@tiagoapp
Copy link

Any new approaches or developments this? @Rich-Harris
All those years by and I just can't find a truly one solution to replicate vue's out-in mode.

It'd be great to have something like

<div transition:fade={{ duration: 300, mode: 'out-in' }}></div>

Or eventually the ability to do with via css classes or something alike...

<div transition:css={{ classes: "fade-in", mode: 'out-in' }}></div>
<div mode:out-in in:fade out:slide></div>

@divStar
Copy link

divStar commented Sep 11, 2022

It's a bummer, that this is really an issue - just encountered this. I'm transitioning a calendar page (almost full size) in/out and when I do so, at some point you can see both of them under one another. 😢

@ImpossibleReality
Copy link

Coming from Vue here. Honestly kind of bummed out to see that this isn't a feature in svelte. It gets really annoying to have to figure out layout shifts manually.

@Garth619
Copy link

I would really love to have the jump controlled by svelte as well. It would be so nice to not have to set up manually with absolute or grid

@speiffer829
Copy link

Glad to see this is hopefully on the horizon. Its one of the biggest "nice little things" coming from Vue that I miss dearly. This would be huge for simple little content changes such as the counter in the demo. Sure theres work arounds like whats used there or the grid thing but it feels totally appropriate and common enough for some "svelte magic" to take the burden off me. More often than not I find myself just having a transition in and no out just so I don't have to deal with the overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests