1

I'm currently trying to create an animation on an H2, using the pseudos ::before and after. But the ::before and ::after are not showing in my HTML. What am I doing wrong here? Looking at styled components docs this should just work. I'm aware of the weird animation function. But this does not have any influence in the before after. I already completely removed it but it still doesn't render.

import React from 'react'
import styled, { keyframes, css } from 'styled-components'
import PropTypes from 'prop-types'

const Wrapper = styled.h2`
  position: relative;
  font-size: 1.5rem;
  color: #ffffff;
  font-weight: 600;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  transform: scale3d(1,1,1);
  opacity: 1;
  &::before, &::after{
    content: ${(props) => props.text};
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    overflow: hidden;
    background: #333333;
    color: #ffffff;
    clip: rect(0, 900px, 0, 0);
  }

  &::before {
    left: 7px;
    text-shadow: 1px 0 green;
    animation: ${glitchEffect} 3s infinite linear alternate-reverse;
  }

  &::after {
    left: 3px;
    text-shadow: -1px 0 red;
    animation: ${glitchEffect} 2s infinite linear alternate-reverse;
  }
`

const glitchEffect = keyframes`
  ${setInterval(createAnimation, 200)}
`

function createAnimation(){
  const single = `clip: rect(${(Math.floor(Math.random() * 100 + 1))}px, 9999px, ${(Math.floor(Math.random() * 100 + 1))}px, 0);`
  return css`${single}`
}
export default function Glitch({ text }){
  return (
    <Wrapper text={text}>{text}</Wrapper>
  )
}

Glitch.propTypes = {
  text: PropTypes.string.isRequired
}

Emiel
  • 37
  • 5

1 Answers1

1

A few things:

content: ${(props) => props.text}; wouldn't work, you need to add double quotes around the text like so content: "${(props) => props.text}";

The second issue is setInterval(createAnimation, 200). This will return an integer (a handle to the interval that you've just created). This will be needed to clear the interval once you're done with the animation for example.

If what you want to do is to generate a some keyframes, then you need to call createAnimation manually like so

import React from "react";
import styled, { keyframes, css } from "styled-components";

const glitchEffect = keyframes`
  from {
    ${createAnimation()}
  }
  to {
    ${createAnimation()}
  }
`;

const Wrapper = styled.h2`
  position: relative;
  font-size: 1.5rem;
  color: #ffffff;
  font-weight: 600;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  transform: scale3d(1, 1, 1);
  opacity: 1;
  > .before,
  > .after {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    overflow: hidden;
    background: #333333;
    color: #ffffff;
    clip: rect(0, 900px, 0, 0);
  }

  > .before {
    left: 7px;
    text-shadow: 1px 0 green;
    animation: ${glitchEffect} 3s infinite linear alternate-reverse;
  }

  > .after {
    left: 3px;
    text-shadow: -1px 0 red;
    animation: ${glitchEffect} 2s infinite linear alternate-reverse;
  }
`;

function createAnimation() {
  const single = `clip: rect(${Math.floor(
    Math.random() * 100 + 1
  )}px, 9999px, ${Math.floor(Math.random() * 100 + 1)}px, 0);`;
  return css`
    ${single}
  `;
}

export default function Glitch({ text }) {
  return (
    <Wrapper>
      <div className="before">{text}</div>
      {text}
      <div className="after">{text}</div>
    </Wrapper>
  );
}

If you want to generate random animation, then you'll need to create the interval from Glitch


// First transform your "animation: ${glitchEffect} 3s infinite linear alternate-reverse;"
// into a "transition: text-shadow 500ms linear;"
// Since we're manually changing its value
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import PropTypes from "prop-types";

const Wrapper = styled.h2`
  position: relative;
  font-size: 1.5rem;
  color: #ffffff;
  font-weight: 600;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  transform: scale3d(1, 1, 1);
  opacity: 1;
  > .before,
  > .after {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    overflow: hidden;
    background: #333333;
    color: #ffffff;
  }

  > .before {
    left: 7px;
    text-shadow: 1px 0 green;
    transition: clip 300ms linear;
  }

  > .after {
    left: 3px;
    text-shadow: -1px 0 red;
    transition: clip 200ms linear;
  }
`;

function createAnimation() {
  return {
    clip: `rect(${Math.floor(Math.random() * 100 + 1)}px, 9999px, ${Math.floor(
      Math.random() * 100 + 1
    )}px, 0)`
  };
}

export default function Glitch({ text }) {
  const [glitchEffect, setGlitchEffect] = useState(createAnimation());
  useEffect(() => {
    const interval = setInterval(() => setGlitchEffect(createAnimation()), 500);
    return () => {
      clearInterval(interval);
    };
  }, []);
  // now pass glitchEffect to a "style" prop to your pseudo elements
  // See https://stackoverflow.com/a/28269950/3877913
  return (
    <Wrapper>
      <div className="before" style={glitchEffect}>
        {text}
      </div>
      {text}
      <div className="after" style={glitchEffect}>
        {text}
      </div>
    </Wrapper>
  );
}

Marouane Fazouane
  • 1,279
  • 14
  • 20