Material-ui: Do keyframe animations work?

Created on 4 Dec 2018  路  9Comments  路  Source: mui-org/material-ui

I'm trying to setup a simple animation with keyframes as explained on JSS but with no luck:

const MyComponentWithStyles = withStyles(() => ({
  "@keyframes fadeAnimation": {
    from: {opacity: 0},
    to: {opacity: 1},
  },
  container: {
    width: "100px",
    height: "100px",
    background: "red",
    animation: "1s fadeAnimation",
  }
}))(MyComponent)

After making some searches I found this FAQ question where it says to use a 'CSS alternative' for keyframe animations. I'm not sure what is intended by 'CSS alternative'. Conventional CSS styling?

Also, this pull request has a comment which says keyframe animations don't work. Not sure how relevant this comment is for my issue.

incomplete

Most helpful comment

For posterity: using a keyframes inside a makeStyles was not working.

The generated animation name was something like makeStyles-keyframes-glowIcon-187 while the animation name placed on CSS rule was simply glowIcon (name used in the JS).

In my environment putting the $ cited by @bjrn fixed the issue:

animation: '$glowIcon 2000ms infinite',

All 9 comments

I ran across this issue just now. According to the JSS docs, one is supposed to put a $ in front of the animation name, which doesn't work. Simply omitting it, just as in your example above, works fine.

@bjrn It depends on the version of JSS you are using.

For posterity: using a keyframes inside a makeStyles was not working.

The generated animation name was something like makeStyles-keyframes-glowIcon-187 while the animation name placed on CSS rule was simply glowIcon (name used in the JS).

In my environment putting the $ cited by @bjrn fixed the issue:

animation: '$glowIcon 2000ms infinite',

For people experiencing this issue:
https://cssinjs.org/jss-syntax/?v=v10.0.0-alpha.10#keyframes-animation

I found one more issues: makeStyles (used as react hook) + function at the style rule level

  1. I discovered that when I provide function at the style rule level using JSS $ref, animation generation crashes:
animation: ({ duration }) =>  `$glitch ${duration}s infinite`

Output:

.makeStyles-root-470::before {}
  1. When I provide animation-name without ref char ($) I can see that rules being generated to animation, but animation-name doesn't refer to @keyframe properly.
animation: ({ duration }) =>  `glitch ${duration}s infinite`

Output:

.makeStyles-root-477::before {
    animation: 1s ease 0s infinite normal none running glitch;
}
  1. String instead of function works fine:
animation: `$glitch 5s infinite`,

Output:

.makeStyles-root-482:before {
    animation: makeStyles-keyframes-glitch-483 5s infinite;
}
  1. Solution/workaround:
 animationDuration: ({ duration }) => `${duration}s`,
 animationIterationCount: 'infinite',
 animationName: `$glitch`,
"@material-ui/core": "^4.1.3",
"@material-ui/icons": "^4.4.1",
"@material-ui/styles": "^4.1.1",

Also TS complains about using function at the style rule level :(

What doesn't works for me in makeStyles():

sslider:  ({urls}) => ({
      background: `url(${urls[0]})`,
      backgroundRepeat: "no-repeat",
      animation: `$slidingBackgroundAnimation 10s`,
     ...
}),
"@keyframes slidingBackgroundAnimation": {
      from: {
        backgroundPositionX: "0px",
      },
      to: {
        backgroundPositionX: "-100px",
      },
},

Here the name of the animation keyframes is rendered badly. Like if the actual animation keyframe slidingBackgroundAnimation is rendered in <head> > <style> as @-webkit-keyframes makeStyles-keyframes-slidingBackgroundAnimation-108 but the sslider css would reference it badly like @-webkit-keyframes makeStyles-keyframes-slidingBackgroundAnimation-109 (with different number).

What works:

sslider: {
      background: ({ urls }) => `url(${urls[0]})`,
      backgroundRepeat: "no-repeat",
      animation: `$slidingBackgroundAnimation 10s`,
     ....
},
"@keyframes slidingBackgroundAnimation" : { ... }

Also, it was huge pain to try to dynamically render @keyframes animationName using props property by using makeStyles({}) passing the props via useStyles({}).

This was the code that didn't work.

const imageSliderAlgo = (urls) => {
 // a function that accepts urls and dynamically create object to be consumed by the keyframes
 // return example for two images

 return {
  "0%": { backgroundImage: `url(${urls[0]})` },
  "50%": { backgroundImage: `url(${urls[1]})` }
 }
};

const useStyles = makeStyles(theme => ({
 "@keyframes slidingBackgroundImageAnimation": ({ urls }) =>
      imageSliderAlgo(urls),
 sslider: { ... }
});

It was not able to get the props, I guess it is due to the fact that props are not properly passed over classNames or higher selectors but works fine when referring the props in the CSS property (as shown by the code in the above section).

After a lot of trials and errors and burning a lot of time, I figured out the best way to get around and dynamically render the keyframes in css-in-js style was wrapping the useStyles() in a custom hook and returning the makeStyles() from there.

const useMyStyles = props => {
  const useStyles = makeStyles(theme => ({
    sslider: {
      background: ({ urls }) => `url(${urls[0]})`,
      animation: `$slidingBackgroundAnimation 30s ease 2s infinite forwards, $slidingBackgroundImageAnimation 20s ease 2s infinite forwards`,
      ...
    },

    // animation 1
    // dynamically rendering keyframes in css-in-js
    // using the props property passed in custom useMyStyles hook while invoking it in main component
    "@keyframes slidingBackgroundImageAnimation": imageSliderAlgo(props.urls),

    // animation 2
    // static keyframes in css-in-jss
    "@keyframes slidingBackgroundAnimation": {
      "0%": {
        backgroundPositionX: "0px",
      },
      "50%": {
        backgroundPositionX: "-120px",
      }
    },
  })); // useStyles closed

  // returning useStyle function with the props passed in the higher order/parent function
  return useStyles(props); 
} // useMyStyles custom hook closed

// Component
export default function SlidingBackground({ children, urls }) {

  // non-working way
  // const classes = useStyles({ urls });

  // working way
  const classes = useMyStyles({ urls });

  return (
    <>
      <div className={classes.sslider}>{children}</div>
    </>
  );
}

Sometimes all that is needed is a custom hook or basically custom function.

For posterity: using a keyframes inside a makeStyles was not working.

The generated animation name was something like makeStyles-keyframes-glowIcon-187 while the animation name placed on CSS rule was simply glowIcon (name used in the JS).

In my environment putting the $ cited by @bjrn fixed the issue:

animation: '$glowIcon 2000ms infinite',

you save my day

Sometimes all that is needed is a custom hook or basically custom function.

Made no difference for me

Was this page helpful?
0 / 5 - 0 ratings