본문 바로가기
개발 공부 일지/React

리액트 - [Styled Component] 글로벌 스타일 / 애니메이션

by yelimu 2024. 8. 12.

createGlobalStyle

<style> 태그를 컴포넌트로 만드는 건데요. 실제로 <style> 태그가 저 위치에 생기는 건 아니고, Styled Components가 내부적으로 처리해서 <head> 태그 안에 우리가 작성한 CSS 코드를 넣어 줍니다.

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  * {
    box-sizing: border-box;
  }

  body {
    font-family: 'Noto Sans KR', sans-serif;
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <div>글로벌 스타일</div>
    </>
  );
}

export default App;

과거에는 애니메이션을 만들 때 프레임 각각을 모두 만들었지만, 요즘에는 움직임의 기준이 되는 프레임만 만들고 그 사이의 프레임들을 자동으로 채워 넣는 방식을 주로 사용합니다. 이때 '움직임의 기준이 되는 프레임'을 '키프레임'이라고 부릅니다.

CSS에서 키프레임은 CSS 애니메이션을 만들 때 기준이 되는 지점을 정하고, 적용할 CSS 속성을 지정하는 문법

<div class="ball"></div>
@keyframes bounce {
  0% {
    transform: translateY(0%);
  }

  50% {
    transform: translateY(100%);
  }

  100% {
    transform: translateY(0%);
  }
}

.ball {
  animation: bounce 1s infinite;
  background-color: #ff0000;
  border-radius: 50%;
  height: 50px;
  width: 50px;
}

 

(CSS)


플레이스 홀더 애니메이션 

<div class="placeholder">
  <div class="placeholder-item a"></div>
  <div class="placeholder-item b"></div>
  <div class="placeholder-item c"></div>
</div
@keyframes placeholder-glow {
  50% {
    opacity: 0.2;
  }
}

.placeholder {
  animation: placeholder-glow 2s ease-in-out infinite;
}

.placeholder-item {
  background-color: #888888;
  height: 20px;
  margin: 8px 0;
}

.a {
  width: 60px;
  height: 60px;
  border-radius: 50%;
}

.b {
  width: 400px;
}

.c {
  width: 200px;
}

placeholder-glow라는 애니메이션 코드는 애니메이션의 중간인 50% 시점에 0.2의 불투명도로 만드는 건데요. 불투명도의 기본값이 1이니까, 불투명도가 0.2로 낮아졌다가 다시 1로 높아지는 애니메이션이 됩니다.

styled component로 구현하기 

import styled, { keyframes } from 'styled-components';

const placeholderGlow = keyframes`
  50% {
    opacity: 0.2;
  }
`;

export const PlaceholderItem = styled.div`
  background-color: #888888;
  height: 20px;
  margin: 8px 0;
`;

const Placeholder = styled.div`
  animation: ${placeholderGlow} 2s ease-in-out infinite;
`;

export default Placeholder;

//App.js
import styled from 'styled-components';
import Placeholder, { PlaceholderItem } from './Placeholder';

const A = styled(PlaceholderItem)`
  width: 60px;
  height: 60px;
  border-radius: 50%;
`;

const B = styled(PlaceholderItem)`
  width: 400px;
`;

const C = styled(PlaceholderItem)`
  width: 200px;
`;

function App() {
  return (
    <div>
      <Placeholder>
        <A />
        <B />
        <C />
      </Placeholder>
    </div>
  );
}

export default App;

로딩 스피너 

@keyframes rotate {
    100% {
      transform: rotate(360deg);
    }
}

.spinner {
  animation: rotate 1.5s linear infinite;
}

CSS

import styled, { keyframes } from 'styled-components';

const rotate = keyframes`
    100% {
      transform: rotate(360deg);
    }
`;
animation: ${rotate} 1.5s linear infinite;

애니메이션을 적용할 부분에 animation 속성을 추가하고 중괄호를 사용해 애니메이션을 넣어 주면 됩니다.

import styled, { keyframes } from 'styled-components';
import spinnerImg from './spinner.png';

const SIZES = {
  large: 24,
  medium: 20,
  small: 16,
};

const StyledInput = styled.input`
  font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
  border: 2px solid ${({ error }) => (error ? `#f44336` : `#eeeeee`)};
  border-radius: ${({ round }) => (round ? `9999px` : `4px`)};
  outline: none;
  padding: 16px;
  position: relative;

  ${({ error }) =>
    !error &&
    `
    &:focus {
      border-color: #7760b4;
    }
  `}
`;

const rotate = keyframes`
    100% {
      transform: rotate(360deg);
    }
`;

const Spinner = styled.div`
  width: 16px;
  height: 16px;
  background-image: url('${spinnerImg}');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  animation: ${rotate} 1.5s linear infinite;
`;

const Container = styled.div`
  width: fit-content;
  position: relative;

  ${Spinner} {
    position: absolute;
    top: calc(50% - 8px);
    right: 20px;
  }
`;

function Input({ loading, ...inputProps }) {
  return (
    <Container>
      <StyledInput {...inputProps} />
      {loading && <Spinner />}
    </Container>
  );
}

export default Input;

 

Styled-Components