I absolutely enjoy using styled-components with React. It's incredibly convenient to write CSS directly within the component file, making everything so simple and intuitive. Plus, the performance boost from loading just the necessary code for the rendered components is fantastic. When I recently wanted to include some animation using the CSS @keyframes
rule, I was initially concerned that I'd need to define it in the global index.css
. Thankfully, I discovered that styled-components can handle animations!
From the styled-components docs:
CSS animations created with @keyframes aren't limited to one component, but you probably don't want them to be global to prevent name clashes. For this reason, we provide a keyframes helper that generates a unique instance for use across your application.
CSS animations created with @keyframes are not limited to just one component, but you also don't want them to be global to prevent any naming conflicts. That's why we provide a keyframes helper that produces a unique instance for your app.
Great! Let’s check out how it functions in real life.
At the beginning, I had a circle displayed in the middle of the page that repeatedly grew and shrank, simulating a breathing exercise. To start with, it was set up in my global CSS definitions.
/* global.css */div.circle {
height: 100px;
width: 100px;
border-style: solid;
border-width: 5px;
border-radius: 50%;
border-color: black;
animation-name: breath-animation;
animation-duration: 8s;
animation-iteration-count: infinite;
}@keyframes breath-animation {
0% { height: 100px; width: 100px; }
30% { height: 400px; width: 400px; opacity: 1 }
40% { height: 405px; width: 405px; opacity: 0.3; }
100% { height: 100px; width: 100px; opacity: 0.6; }
}
This setup works perfectly — every time I render a div
with className='circle'
, I get a beautifully animated circle. The issue is, I only need to render it in a single component. As a result, there’s a significant amount of code being loaded even when it’s not always necessary.
Let's rewrite this using styled-components right inside my Breathe
component. To start, we'll simply render the circle div
.
// src/components/breathe.jsimport React from 'react'
import styled from 'styled-components'const Breathe = () => {
return (
<Container>
<Circle />
</Container>
)
}const Circle = styled.div`
height: 100px;
width: 100px;
border-style: solid;
border-width: 5px;
border-radius: 50%;
border-color: black;
`const Container = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 450px;
`
Fantastic, we've successfully rendered a circle within a flex container. This specific component is the sole one requiring the full CSS setup, hence it's only loaded when this particular component is utilized.
To add the animation, you'll need to bring in the keyframes
helper from styled-components. You can do this by using the following import statement: import { keyframes } from 'styled-components'
. After that, you can define the animation similarly to how you define a component.
// src/components/breathe.jsimport { keyframes } from 'styled-components'const breatheAnimation = keyframes`
0% { height: 100px; width: 100px; }
30% { height: 400px; width: 400px; opacity: 1 }
40% { height: 405px; width: 405px; opacity: 0.3; }
100% { height: 100px; width: 100px; opacity: 0.6; }
`
To combine everything, let's include the animation parameters within the definition of our Circle
component.
// src/components/breathe.jsimport React from 'react'
import styled, { keyframes } from 'styled-components'const Breathe = () => {
return (
<Container>
<Circle />
</Container>
)
}export default Breatheconst breatheAnimation = keyframes`
0% { height: 100px; width: 100px; }
30% { height: 400px; width: 400px; opacity: 1 }
40% { height: 405px; width: 405px; opacity: 0.3; }
100% { height: 100px; width: 100px; opacity: 0.6; }
`const Circle = styled.div`
height: 100px;
width: 100px;
border-style: solid;
border-width: 5px;
border-radius: 50%;
border-color: black;
animation-name: ${breatheAnimation};
animation-duration: 8s;
animation-iteration-count: infinite;
`const Container = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 450px;
`
And that’s that!