skip to Main Content

I need to apply the following entering and leaving animation

They are presented using tailwindcss classes

      Entering: "transform ease-out duration-300 transition"
        From: "translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
        To: "translate-y-0 opacity-100 sm:translate-x-0"
      Leaving: "transition ease-in duration-100"
        From: "opacity-100"
        To: "opacity-0"

I tried to use the following but doesn’t seem to work.

@tailwind base;
@tailwind components;
@tailwind utilities;


@layer components {
  .alt-pop {
    animation: alt-pop-enter, alt-pop-leave;
  }
  @keyframes alt-pop-enter {
    @apply transform ease-out duration-300 transition;
    from { @apply translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2; }
    to   { @apply translate-y-0 opacity-100 sm:translate-x-0; }
  }
  @keyframes alt-pop-leave {
    @apply transition ease-in duration-100;
    from { @apply opacity-100; }
    to   { @apply opacity-0; }
  }
}

My suspicions are that:

  1. keyframes doesn’t work with @apply
  2. keyframes work exclusively with from and to, so cannot add extra css styles within the keyframe

How do I use css as much as possible to setup this entering and leaving animation instead of JS?

And how do I use tailwindcss classes as much as possible?

And how do I set the delay before switching from entering to leaving?

One approach I can think of is convert all the tailwind classes back to the actual tailwind then write my own keyframes and animation css class.

Is there a better approach than this?

3

Answers


  1. There are some invalid syntax/conceptions with the provided code:

    .alt-pop {
      animation: alt-pop-enter, alt-pop-leave;
    }
    

    This applies both of these named animations at the same time – probably not you’d want. Also note that no duration has been provided so the duration for both these animations is 0s and thus there would be no visual effect.

    @keyframes alt-pop-enter {
      @apply transform ease-out duration-300 transition;
      /* … */
    }
    @keyframes alt-pop-leave {
      @apply transition ease-in duration-100;
      /* … */
    }
    

    You can’t use @apply as immediate "child" of @keyframes, since this would conceptually output something like:

    @keyframes alt-pop-enter {
      transform: /* … */;
      transition-timing-function: /* … */;
      /* … */
    }
    

    And this is invalid CSS.

    @apply transform ease-out duration-300 transition;
    /* … */
    @apply transition ease-in duration-100;
    
    

    It feels like you are trying to manipulate the animation, but you are using classes that set transition-* properties. These properties do not affect animation.


    How do I use css as much as possible to setup this entering and leaving animation instead of JS?

    There will always be some aspect of JavaScript needed, since the CSS needs to be applied on the event when the animation needs to play.

    And how do I use tailwindcss classes as much as possible?

    Use your existing solution with the enter/leave classes.

    And how do I set the delay before switching from entering to leaving?

    This would be best done in the JavaScript that controls the enter/leaving classes. Otherwise, you could add a delay-* class to the leaving set of classes.

    One approach I can think of is convert all the tailwind classes back to the actual tailwind then write my own keyframes and animation css class.
    Is there a better approach than this?

    Yes, your existing enter/leave classes.


    Edit 1: Reply to @Kim Stacks

    "What about the answer provided by Rifky Niyas at stackoverflow.com/a/75715839/80353? there’s also a sandbox example of his solution. It seems that it’s possible to do so without any JS"

    It might seem working, but if you see keenly, your asked requirement is not met. Further I would refer your own comment to prove my point.

    How is the transform and transition in Entering and transition in Leaving handled?

    also in your sandbox example in play.tailwindcss, i expected the div to be completely hidden in the end because opacity-0, but it’s still visible to me at the end. Am I missing something?

    @keyframes alt-pop-enter {
      from {
        @apply translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2;
      }
      to {
        @apply translate-y-0 opacity-100 sm:translate-x-0;
      }
    }
    

    Adding on you can’t use variants in @keyframes since it would produce invalid CSS. In this instance, you’d create a separate @keyframes for the sm: case and then apply that to the .alt-pop class. Something like:

    .alt-pop {
      animation: 300ms ease-out alt-pop-enter, 100ms ease-in 500ms alt-pop-leave;
    }
    
    @media screen(sm) {
      .alt-pop {
        animation: 300ms ease-out alt-pop-enter-sm, 100ms ease-in 500ms alt-pop-leave;
      }
    }
    
    @keyframes alt-pop-enter {
      from {
        @apply translate-y-2 opacity-0;
      }
      to {
        @apply translate-y-0 opacity-100;
      }
    }
    
    @keyframes alt-pop-enter-sm {
      from {
        @apply opacity-0 translate-x-2;
      }
      to {
        @apply opacity-100 translate-x-0;
      }
    }
    

    Edit 2: Reply to @Rifky Niyas

    Your @keyframes compile to:

    @keyframes alt-pop-enter {
      from {
        --tw-translate-y: 0.5rem;
        transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
        opacity: 0;
      }
    
      @media (min-width: 640px) {
        from {
          --tw-translate-y: 0px;
          --tw-translate-x: 0.5rem;
          transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
        }
      }
    
      to {
        --tw-translate-y: 0px;
        transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
        opacity: 1;
      }
    
      @media (min-width: 640px) {
        to {
          --tw-translate-x: 0px;
          transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
        }
      }
    }
    

    Where the @media rules inside the @keyframes is invalid CSS

    Login or Signup to reply.
  2. @apply is a feature of tailwindcss that allows you to extract a set of CSS declarations as a class and apply it to an element. You can use it to simplify writing and maintain CSS styles.

    Keyframes, on the other hand, define the intermediate steps in an animation. They are not applied directly to an element. You can reference them in an animation definition.

    So, No, it is not possible to use @apply in tailwindcss for keyframes.

    You can though achieve what you want like below:

    @keyframes alt-pop-enter {
      0% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }
    
    .enter {
      animation: alt-pop-enter 1s;
    }
    
    Login or Signup to reply.
  3. The recommended approach

    The approach recommended in the documentation inorder to define custom animations you would require to define @keyframes and animation properties in tailwind.config.js file and apply via the animate-my-animation-name class.

    The above approach requires you to mostly use the conventional CSSinstead of tailwind classes. But coming back to your original requirements,

    How do I use css as much as possible to setup this entering and
    leaving animation instead of JS?

    And how do I use tailwindcss classes as much as possible?

    Yes, you can achieve this by mostly using tailwind classes using the following approach.

    Using @apply in @keyframes

    First let’s try solving your suspicions

    My suspicions are that:

    1. keyframes doesn’t work with @apply
    2. keyframes work exclusively with from and to, so cannot add extra css styles within the keyframe

    According to the docs for the @apply directive,

    Use @apply to inline any existing utility classes into your own custom
    CSS.

    When we are defining a @keyframes rule, the CSS styling is applied within from and to blocks in order to define styles for the waypoints within the animation. So your animation style definition would look like this.

    @keyframes alt-pop-enter {
      from {
        @apply translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2;
      }
      to {
        @apply translate-y-0 opacity-100 sm:translate-x-0;
      }
    }
    @keyframes alt-pop-leave {
      from {
        @apply opacity-100;
      }
      to {
        @apply opacity-0;
      }
    }
    

    Error in applying animation

    The following lines in your code is invalid when applying CSS animations.

    @apply transform ease-out duration-300 transition;
    @apply transition ease-in duration-100;
    

    You seem to have tried to use transition property inside @keyframes together. In CSS animation and transition are two different ways to animate an object. You can read more here. As mentioned in MDN docs above

    The @keyframes CSS at-rule controls the intermediate steps in a CSS
    animation sequence by defining styles for keyframes (or waypoints)
    along the animation sequence.

    Also note that the property transform class isn’t required in tailwind Version 3 since the transform values such as rotate, scale, etc are applied via individual styles such as rotate-1 and scale-50 instead of adjusting tailwind variables as in version 2

    Fixing the animation

    Now since we are having two separate animations to be defined, we need to use a custom CSS property to extract a separate class. We can make use of animation shorthand property. For our purpose, the order of animation property values would look like this

    duration | easing-function | delay | name, duration | easing-function | delay | name
    

    Here is how it would look in CSS code

    .alt-pop {
       animation: 300ms ease-out alt-pop-enter, 100ms ease-in 500ms alt-pop-leave;
    }
    

    Notice we add an extra 500ms value to animation for it to delay by 500ms after the animation has started. This includes 300ms for the initial animation to occur and then another 00ms pause before the second animation inititaes. Then you can apply the class to HTML element and use as required

    <div class="alt-pop">Content</div>
    

    Here is a link to the solved animation: https://play.tailwindcss.com/uLgEAAd5Of?file=css

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search