개발 공부 기록하기/07. react.js & vue.js

React Styled Component 정리

lannstark 2020. 11. 10. 21:58

올해 10월 초부터 생각했던 사이드 프로젝트를 본격적으로 만들어 보려고 한다 (이번엔 제발 런칭까지....)

리액트를 거의 3년만에 보게 되었는데 뭐 아주 그냥 새롭다. 이야 훅은 또 뭐야? 라떼는 클래스만 있었는데

이번 포스트에서는 리액트에서 스타일 지정하는 방법을 공부해 보았다.

(react modern stack에 빠삭한 지인과의 카톡)

REF : https://react.vlpt.us/styling/03-styled-components.html

  • CSS in Js : JS 안에 CSS를 작성하는 것
  • 리액트 진영에서 가장 인기 있는 CSS in JS 라이브러리가 바로 styled-components 이다.

설치

yarn add styled-components

사용

styled.태그이름 을 사용해서 바로 Recat component를 만들 수 있다.

import React from 'react';
import styled from 'styled-components';

/**
 * Styled Components를 이용해 컴포넌트까지 같이 만든다
 */
const Circle = styled.div`
  width: 5rem;
  height: 5rem;
  background: black;
  border-radius: 50%;
`;

export default Circle;

오호.. props를 이용해 css 옵션을 하나만 조정할 수도 있고, 여러 css를 조절할 수도 있다.

const Circle = styled.div`
  width: 5rem;
  height: 5rem;
  background: ${props => props.color || 'black'};
  border-radius: 50%;
  ${props =>
    props.huge &&
    css`
      width: 10rem;
      height: 10rem;
    `}
`;

<Circle
  color="red" huge
/>

신기하네 ㅋㅋㅋㅋㅋ Sass의 lighten() 혹은 darken() 과 같은 유틸 함수를 쓰고 싶다면 polished 라이브러리를 이용할 수 있다.

yarn add polished
import {lighten, darken} from 'polished';

const StyledButton = styled.button`
  /* 색상 */
  background: #228be6;
  &:hover {
    background: ${lighten(0.1, '#228be6')};
  }
  &:active {
    background: ${darken(0.1, '#228be6')};
  }
`

function Button({ children, ...rest }) {
  return <StyledButton {...rest}>{children}</StyledButton>;
}

export default Button;

이렇게 하면 야무지게 적용 완료! 키야 RGB 찾으러 갈 필요가 없네 (흑흑 이런거 볼 때마다 프론트 옛날 사람이 된 것 같다...)

styled components의 ThemeProvider 기능을 사용하면 styled components로 만드는 모든 컴포넌트에서 조회할 수 있는 global 값이 된다고 한다. 오호...

/* Button을 쓰는 쪽 render 코드 */
<ThemeProvider theme={{
  rgbColors: {
    blue: '#228be6',
    gray: '#495057',
    pink: '#f06595'
  }
}}>
  <AppBlock>
    <Button>BUTTON</Button>
  </AppBlock>
</ThemeProvider>
/* Button 코드 style 부분 */
/* 색상 */
${props => {
  const selected = props.theme.rgbColors.blue
  return css`
    background: ${selected};
    &:hover {
      background: ${lighten(0.1, selected)};
    }
    &:active {
      background: ${darken(0.1, selected)};
    }    
  `   
}};

여기서 이제 props.theme.rgbColors.blueprops.theme.rgbColors[props.color]로 바꿔주고 default prop을 설정해주면 깔끔~ 해진다

/* Button 코드 style 부분 */
${props => {
  const selected = props.theme.rgbColors[props.color]
  // 나머지는 그대로
}};

/* function Button 아래 부분 */
Button.defaultProps = {
  color: 'blue'
};

const selected = props.theme.rgbColors[props.color]가 보기 불편하면 다음과 같이 바뀔 수 있다.

/* Button 코드 style 부분, 여기서 props 대신 { }로 바뀐다 */
${({ theme, color }) => {
  const selected = theme.palette[color];
  // 나머지는 그대로
}};

// color를 명시적으로 넣어줌
function Button({ children, color, ...rest }) {
  return (
    <StyledButton color={color} {...rest}>
      {children}
    </StyledButton>
  );
}

스타일 역시 동적인 부분과 정적인 부분을 분리할 수 있다.

const dynamicStyle = css`
  ${props => (
        // 로직
  )}
`

const staticStyle = styled.button`
  // 정적인 style 다 넣어놓고~
  ${dynamicStyle}
`

css를 중첩되게 넣을 수 있다.

const DialogBlock = styled.div`
  h3 {}
  p {}
`;

// h3과 p에 각각 style이 적용된다
<DialogBlock>
  <h3>하하하</h3>
  <p>히히</p>
</DialogBlock>

styled-components로 컴포넌트의 스타일을 특정 상황에서 덮어 쓸 수 있다.

이때 해당 컴포넌트에서 className props를 내부 element에게 전달해주고 있는지 확인이 필요하다.

// Button 컴포넌트가 있을 때
// & + &를 하게 되면, 같은 부모를 가지는 Button 옆에 Button에만 적용된다
const ShortMarginButton = styled(Button)`
  & + & {
    margin-left: 0.5rem;
  }
`;

// CASE 1. className을 명시적으로 전달 중
const Button = ({ className }) => {
  return <div className={className}></div>
}

const NewComponent = styled(Button)`
  background: black;
`;

// CASE 2. rest로 전달 중
function Button({ children, ...rest }) {
  return <StyledButton {...rest}>{children}</StyledButton>;
}

트랜지션 효과를 적용할 때는 @keyframes를 사용하게 된다. keyframes 규칙은 개발자가 애니메이션 중간중간의 특정 지점들을 거칠 수 있는 키프레임들을 설정함으로써 CSS 애니메이션 과정의 중간 절차를 제어하는 것이다. 이 룰은 브라우저가 자동으로 애니메이션을 처리하는 것 보다 더 세밀하게 중간 동작들을 제어할 수 있다.

styled-components에서 이를 사용할 때는 keyframes라는 유틸을 써야 한다.

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

const fadeIn = keyframes`
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
`;

const slideUp = keyframes`
  from {
    transform: translateY(200px);
  }
  to {
    transform: translateY(0px);
  }
`;

const DarkBackground = styled.div`
  // 기존 CSS는 그대로

  animation-duration: 0.25s;
  animation-timing-function: ease-out;
  animation-name: ${fadeIn};
  animation-fill-mode: forwards;
`

const DialogBlock = styled.div`
  // 기존 CSS는 그대로

  animation-duration: 0.25s;
  animation-timing-function: ease-out;
  animation-name: ${slideUp};
  animation-fill-mode: forwards;
`

이렇게 하면 나타낼 때 트랜지션 효과가 나타나게 된다. 오호 애니메이션 관련 css는 잘 모르는데 신기하다 ㅋㅋㅋ

사라질때를 처리하려면 local prop 들이 더 필요하다고... 오호.. 신기하다. 애니메이션 직접 만질일 있으면 다시 봐야겠다 ㅋㅋㅋ

Global

createGlobalStyle을 이용하여 CSS 속성을 덮어 쓸 수도 있다.

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

const GlobalStyle = creaetGlobalStyle`
  body {
    padding: 0;
    margin: 0;
  }
`

<React.Fragment>
  <GlobalStyle>    //    <-- 추가
  <Button>Hello</Button>
  <Button danger>Hello</Button>
</React.Fragment>