skip to Main Content

Basicly, i have an Svelte component that represend some kind of tag, there is icon in it. On hover i show a title on the side.

<div class="flex flex-row items-center gap-2 bg-black bg-opacity-70 backdrop-blur-sm p-3 rounded-2xl icon_container" on:mouseenter={toggleVisibility} on:mouseleave={toggleVisibility}>
    <div>
        {@html icon}
    </div>
    {#if visible}
        <p transition:fly={{ x: -50, duration: 500 }}>{title}</p>
    {/if}
</div>

Right now, container enlarge insantly, but i want it to be a little smoother.

So, how can i make this animation smoother?

gif for better understanding example

I’ve made a little workaround – just strictly asign a bigger width, but if title is bigger or smaller, it’s creating a weird looking gap between title and icon.

.icon_container {
      transition: .3s;
      width: 56px;

      &:hover {
        width: 200px;
      }
    }

2

Answers


  1. You could use Svelte’s tweened to change the size of the container instead of relying on CSS to change the width which will give janky results.

    Here’s a rudimentary example in the REPL https://svelte.dev/repl/b704f0829a4b4c10a58ec65ff1f4319e?version=3.58.0

    In this example I’m passing the width of the text into the child component and using tweened to switch between the width that is only the icon and the width that includes the text.

    The important part is adding the tweened store and toggling it with your visible variable

    let visible
    export let textWidth
    
    const containerWidth = tweened(56, {
        duration: 700,
        easing: quintOut,
        ...
    })
    
    function toggleVisibility() {
        visible = !visible
    }
    
    $: visible? $containerWidth = textWidth : $containerWidth = 56
    

    And then using the $containerWidth tweened store as the width in your container’s style tag:

    <div style="width: {$containerWidth}px">...</div>
    

    Doing it this way allows you more creativity with how elements come into and out of the container’s "frame" since you get more finite timing and easing controls.

    Login or Signup to reply.
  2. By wrapping the title in an additional element, Svelte’s fly and slide transition with the recently added axis: 'x' option could be combined. (since 3.56.0) Like this no manual adjustment of the width of the elements would be necessary.

    REPL

    <script>
        import {slide, fly} from 'svelte/transition'
        import {icons} from './icons'
    
        export let itemName
        export let title
    
        let visible = false
    </script>
    
    <div class="item"
             on:mouseenter="{() => visible=true}"
             on:mouseleave="{() => visible=false}"
             >
        <div class="icon">
            <svg viewBox="0 0 100 100" width="20" xmlns="http://www.w3.org/2000/svg">
                {@html icons[itemName]}     
            </svg>
        </div>
        {#if visible}
        <div class="title-wrapper" 
                 in:slide="{{axis: 'x', duration: 400}}"
                 out:slide="{{axis: 'x', duration: 400, delay: 150}}"
                 >
            <div class="title" 
                     in:fly="{{ x: -50, duration: 500, delay: 150 }}"
                     out:fly="{{ x: -50, duration: 500}}"
                     >
                {title}
            </div>
        </div>
        {/if}
    </div>
    
    <style>
        .item {
            display: flex;
            background: lightgrey;
            padding: .3em;
            border-radius: .3rem;
        }
        .item > div {
            padding: .2em;
        }
        .title {
            line-height: 1;
            font-size: 20px;
            font-weight: bold;
            white-space: nowrap;
        }
        svg {
            display: block;
        }
    </style>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search