Search code examples
cssreactjscss-animationscss-modules

CSS Modules and CSS keyframe animations


I am trying to do a simple animation using React, keyframes, CSS modules (and SASS). The problem is that CSS Modules hash keyframe names the same way it hashes the local classes.

JS code

//...

export default () => {
  const [active, setActive] = useState(false);
  return(
    <div className={active ? 'active' : 'inactive'}
      onClick={() => setActive(!active)}
    >content</div>
  )
}

An attempt to make everything global, used this source as a tutorial (does not compile):

//default scope is local

@keyframes :global(animateIn) {
  0% { background: black; }
  100% { background: orange; }
}

@keyframes :global(animatOut) {
  0% { background: orange; }
  100% { background: black; }
}

:global {
  .active {
    background: orange;

    animation-name: animateIn;
    animation-duration: 1s;
  }

  .inactive {
    background: black;

    animation-name: animateOut;
    animation-duration: 1s;
  }
}

Changing this does not work too:

:global {
  @keyframes animateIn {
    0% { background: black; }
    100% { background: orange; }
  }

  @keyframes animateOut {
    0% { background: orange; }
    100% { background: black; }
  }
}

Another attempt (does not work):

@keyframes animateIn {
  0% { background: black; }
  100% { background: orange; }
}

@keyframes animateOut {
  0% { background: orange; }
  100% { background: black; }
}

:global {
  .active {
    background: orange;

    :local {
      animation-name: animateIn;
    }
    animation-duration: 1s;
  }

  .inactive {
    background: black;

    :local {
      animation-name: animateOut;
    }
    animation-duration: 1s;
  }
}

How to use keyframes in CSS modules global scope? Is it possible to use local scope keyframes in a global scope class?


Solution

  • Your third attempt was almost fine, you just have to add & before :local and make sure there's a space in between them. By doing so, you switch to the local scope within the selector.

    :global {
        .selector {
            & :local {
                animation: yourAnimation 1s ease;
            }
        }
    }
    
    @keyframes yourAnimation {
        0% {
            opacity: 0;
        }
        to {
            opacity: 1;
        }
    }
    

    Which compiles to

    .selector {
        animation: [hashOfYourAnimation] 1s ease;
    }