React function components with context
by rafaelaferro
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<div id="app"></div>
SCSS
body {
background: #111020;
}
.app {
display: flex;
gap: 20px;
padding: 50px;
}
/*
mixin to create a glitch effect animation
- $nth-child: specifies the layer number (default is 1)
- $frames: specifies the number of animation frames (default is 20)
- $duration: specifies the duration of the animation (default is 2 seconds)
- $delay: specifies the delay before the animation starts (default is 0 seconds)
*/
@mixin glitch-animation($nth-child: 1,
$frames: 20,
$duration: 2s,
$delay: 0s) {
// 1. HUE TONES
// Color each layer differently based on $nth-child
@if $nth-child==1 {
// You can tweak the hue-rotate values in each layer, to achieve
// a different color palette
filter: sepia(100%) saturate(300%) brightness(120%) hue-rotate(240deg);
}
@else if $nth-child==2 {
filter: sepia(100%) saturate(300%) brightness(150%) hue-rotate(520deg);
}
@else if $nth-child==3 {
filter: sepia(100%) saturate(300%) brightness(120%) hue-rotate(90deg);
}
/* Generate a name for each layer so they animate differently */
$name: glitch-animation-#{unique-id()};
@keyframes #{$name} {
@for $i from 0 through $frames {
#{percentage($i * (1 / $frames) / 3)} {
// 2. CROP
$top-limit: random() * 100%;
$bottom-limit: random() * 100%;
clip-path: polygon(
0% $top-limit,
100% $top-limit,
100% $bottom-limit,
0% $bottom-limit
);
// 3. OFFSET
@for $i from 1 through 3 {
@if $nth-child == $i {
// Offset the layer position in proportion to image size
// (between -3% and 3% in each direction)
$translate-x: random() * 6% - 3%;
$translate-y: random() * 6% - 3%;
transform: translate(calc(-50% + #{$translate-x}), $translate-y);
}
}
}
}
/* Stop animating the crop to pause the glitch for two-thirds of the frames */
...
React
function App() {
return (
<div className="app">
<Glitch src="https://www.rafaelaferro.com/assets/images/blogposts/glitch-effect/mimi.jpg" alt="The most beautiful cat ever seen" width={200} height={200} />
<Glitch src="https://www.rafaelaferro.com/assets/images/blogposts/glitch-effect/mimi-2.jpg" alt="The most beautiful cat ever seen" width={100} height={100} />
<Glitch src="https://www.rafaelaferro.com/assets/images/blogposts/glitch-effect/mimi-2.jpg" alt="The most beautiful cat ever seen" width={50} height={50} />
</div>
);
}
function Glitch({ src, alt, width, height }) {
return (
<div className="glitch-wrapper">
<img src={src} alt={alt} width={width} height={height} />
{/*
Using lodash for simplicity but you can
manually repeat the html element
*/}
{_.times(3, i => (
<img
key={i}
className="glitch-layer"
src={src}
alt=""
width={width}
height={height}
/>
))}
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#app"))