How to use two svelte transitions on the same togglable element?
Asked Answered
S

2

12

I have an input field that I want to hide/show and doing so with a fade and slide transition. I've have two examples that I came up with but both have their drawbacks and I'd like to know if there is a more elegant solution.

I just need one of the two questions to be answered as both of them would solve my problem.

Question 1: Is there a way to trigger multiple transitions for one transition-directive?

Question 2: How to add a class that will trigger an ordinary css-transition after an if-statement put the element in the DOM?

Example 1

Svelte does not allow two transitions on the same element. So one solution is to nest two elements as shown below. Is there instead a way to write a custom transition using both fade and slide transition:myMultiTransition?

{#if active === true}
  <span transition:fade>
    <span transition:slide>
      <input type="text" />
    </span>
  </span>
{/if}

Example 2

In my other solution I just toggle an active class using a normal css transitions. The problem here is that the <input>-field never leaves the DOM. It's 0px height but it seems wrong to leave it there.

How to cuccessfully show the input field with an {#if active === true} and afterwards add a class that trigger the transition effect? Svelte seems to add the active-class that is supposed to trigger the transition before the element has entered the DOM.

I've tried to use await tick(), onMount, beforeUpdate in various combination with no luck.

When adding the class with a delay with setTimeout it works - but I don't like this solution because it could fail if not the timing is exact and I won't want a delay before the transition start.

<span class:{active}>
   <input type="text" />
</span>

<style>
  .active {
     // Normal transition: opacity 1s etc ... 
  }
</style>

REPL

https://svelte.dev/repl/89cb7d26d9484d0193b4bc6bf59518ef?version=3.38.3

Scranton answered 3/7, 2021 at 11:41 Comment(0)
N
8

You can create your own transition function:

<script>
    import { cubicOut } from 'svelte/easing';
    let visibleDoubleElements = false;


    function slidefade(node, params) {
        const existingTransform = getComputedStyle(node).transform.replace('none', '');

        return {
            delay: params.delay || 0,
            duration: params.duration || 400,
            easing: params.easing || cubicOut,
            css: (t, u) => `transform-origin: top left; transform: ${existingTransform} scaleY(${t}); opacity: ${t};`
        };
    }
</script>


<label>
    <input type="checkbox" bind:checked={visibleDoubleElements}>
    Svelte transition
</label>

{#if visibleDoubleElements === true}
    <input transition:slidefade type="text" placeholder="Double elements" />
{/if}

REPL: https://svelte.dev/repl/da8880947eff4f32b740a8742d9f817e?version=3.38.3

Nineteen answered 3/7, 2021 at 12:31 Comment(2)
Please add relevant code snippet in the answer – Sutton
That was indeed what I was looking for. Thank you! πŸ™ I could never figure out how to use the custom transition function by myself. svelte.dev/tutorial/custom-css-transitions – Scranton
P
3

It might be the easiest to stick with the first solution you already provided: adding a wrapper for each transition.

If you want to reuse a specific combination of transitions it might be worth it to write your own one. At this point you can try to use the implementation from Svelte: Here is an example for Slide + Fade

function fadeSlide(node, options) {
    const slideTrans = slide(node, options)
    return {
        duration: options.duration,
        css: t => `
            ${slideTrans.css(t)}
            opacity: ${t};
        `
    };
}

https://svelte.dev/repl/f5c42c6dc6774f29ad9350cd2dc2d299?version=3.38.3

Generic Solution (Theoretical)

In Svelte the transitions itself don't rely on CSS-transitions. A Svelte transition only provides the style for each transition step. Therefore a generic solution would be to create a merge-transition that takes 2..N transition functions and puts the styles from the individual transition together. Unfortunately this is not always trivial due to conflict situations in CSS.

E.g. combining two transitions... one where the opacity should be 0 and the other with a target opacity of 0.5. Question is: What should the output look like? If 0 is expected then there must be some logic which converts "opacity: 0; opacity: 0.5;" to "opacity: 0;". And there are surely more complex cases.

Panchromatic answered 3/7, 2021 at 17:55 Comment(2)
This isn't quite accurate. CSS absolutely supports transitioning multiple properties: developer.mozilla.org/en-US/docs/Web/CSS/transition – Krystakrystal
@NikolasStevenson-Molnar Thank you for your feedback. Yea, my answer was not very clear. I basically just wanted to point out possible conflict situations in CSS. In fact CSS transitions (and the timings) don't matter in this case. I have updated my answer. – Panchromatic

© 2022 - 2024 β€” McMap. All rights reserved.