search

Home  >  Q&A  >  body text

Apple animation issue using React and inline CSS

I'm trying to recreate this animation in React using HTML and CSS, using inline styles and TypeScript. I'm creating an object with style information and referencing it in the style attribute. Below is the code. It doesn't work, I'm not sure what I'm doing wrong, I suspect the styles aren't defined and referenced correctly?

This is the original Codepen example I tried to rewrite: Apple Animation

This is my code

import React from 'react';

const styles = {
    
    '@keyframes showTopText': {
        '0%': { transform: 'translate3d(0, 100%, 0)' },
        '40%, 60%': { transform: 'translate3d(0, 50%, 0)' },
        '100%': { transform: 'translate3d(0, 0, 0)' },
    },
    '@keyframes showBottomText': {
        '0%': { transform: 'translate3d(0, -100%, 0)' },
        '100%': { transform: 'translate3d(0, 0, 0)' },
    },

    animatedTitle: {
        color: '#222',
        fontFamily: 'Roboto, Arial, sans-serif',
        height: '90vmin',
        left: '50%',
        top: '50%',
        transform: 'translate(-50%, -50%)',
        width: '90vmin',
    },
    'animatedTitle > div': {
        height: '50%',
        overflow: 'hidden',
        position: 'absolute',
        width: '100%',
    },
    'animatedTitle > div div': {
        fontSize: '12vmin',
        padding: '2vmin 0',
        position: 'absolute',
    },
    'animatedTitle > div div span': {
        display: 'block',
    },
    'animated-title > div.text-top': {
        borderBottom: '1vmin solid #000',
        top: 0,
    },
    'animatedTitle > div.text-top div': {
        animation: 'showTopText 1s',
        animationDelay: '0.5s',
        animationFillMode: 'forwards',
        bottom: 0,
        transform: 'translate(0, 100%)',
    },
    'animatedTitle > div.text-top div span:first-child': {
        color: '#767676',
    },
    'animatedTitle > div.text-bottom': {
        bottom: 0,
    },
    'animatedTitle > div.text-bottom div': {
        animation: 'showBottomText 0.5s',
        animationDelay: '1.75s',
        animationFillMode: 'forwards',
        top: 0,
        transform: 'translate(0, -100%)',
    },
};

function Design() {
    return (
        <div style={styles.animatedTitle}>
            <div style={styles['animatedTitle > div.text-top div']}>
                <div>
                    <span>mimicking</span>
                    <span>apple's design</span>
                </div>
            </div>
            <div style={styles['animatedTitle > div.text-bottom']}>
                <div>for the win!</div>
            </div>
        </div>
    );
}

export { Design };

P粉729436537P粉729436537322 days ago329

reply all(1)I'll reply

  • P粉115840076

    P粉1158400762024-01-11 10:37:49

    You can try to use styled-components to make your components more flexible and compatible. I copied codepen's example using styled-components and made it easy to extend.

    Therefore, TopAnimateBlock and BottomAnimateBlock both have numOfLine properties, indicating how many lines are within the block. The second property in BottomAnimateBlock is delayTopLine which should be the same number as numOfLine in TopAnimateBlock because we need to wait for the top OK to play.

    Additionally, you can easily change the text color via the color property of TextStyle and pass the color value, HEX color or rgba() / hsla().

    TextAnimation.tsx

    import styled, { keyframes } from 'styled-components';
    
    const showTopText = keyframes`
      0% { transform: translate3d(0, 100% , 0); }
      40%, 60% { transform: translate3d(0, 50%, 0); }
      100% { transform: translate3d(0, 0, 0); }
    `;
    const showBottomText = keyframes`
      0% { transform: translate3d(0, -100%, 0); }
      100% { transform: translate3d(0, 0, 0); }
    `;
    
    const Section = styled.section`
      width: calc(100% + 10vmin);
      display: flex;
      flex-flow: column;
      padding: 2vmin 0;
      overflow: hidden;
      &:last-child {
        border-top: 1vmin solid white;
      }
    `;
    
    const Block = styled.div<{ numOfLine: number }>`
      position: relative;
    `;
    const TopAnimateBlock = styled(Block)`
      animation: ${showTopText} calc(0.5s * ${props => props.numOfLine}) forwards;
      animation-delay: 0.5s;
      transform: translateY(calc(100% * ${props => props.numOfLine}));
    `;
    const BottomAnimateBlock = styled(Block)<{ delayTopLine: number }>`
      animation: ${showBottomText} calc(0.5s * ${props => props.numOfLine}) forwards;
      animation-delay: calc(0.7s * ${props => props.delayTopLine});
      transform: translateY(calc(-100% * ${props => props.numOfLine}));
    `;
    
    const TextStyle = styled.p<{ color: string }>`
      font-family: Roboto, Arial, sans-serif;
      font-size: 12vmin;
      color: ${props => props.color};
    `;
    
    export const TextAnimation = () => {
      return (
        <>
          <Section>
            <TopAnimateBlock numOfLine={2}>
              <TextStyle color="grey">mimicking</TextStyle>
              <TextStyle color="white">apple's design</TextStyle>
            </TopAnimateBlock>
          </Section>
          <Section>
            <BottomAnimateBlock numOfLine={1} delayTopLine={2}>
              <TextStyle color="white">for the win!</TextStyle>
            </BottomAnimateBlock>
          </Section>
        </>
      );
    };
    

    If we want to animate 3 rows instead of 2, just add/change:

    1. Add new TextStyle component
    2. Changed numOfLine from 2 to 3 in TopAnimateBlock and delayTopLine from 2 to 3## in BottomAnimateBlock
    3. # and replace the keyframes with the following clips:
    4. const showTopText = keyframes`
        0% { transform: translate3d(0, 100% , 0); }
        25%, 40% { transform: translate3d(0, 66%, 0); }
        60%, 75% { transform: translate3d(0, 33%, 0); }
        100% { transform: translate3d(0, 0, 0); }
      `;
      

      reply
      0
  • Cancelreply