[React #9] styled-components로 효과적인 스타일링

현대 앱이 컴포넌트를 기반으로 발전해가면서 CSS 스타일링 방법론 또한 '컴포넌트를 기반'으로 재구성되고 있다. 이러한 발전 속에서 등장한 패러다임이 'CSS-in-JS'이며 그 중 가장 인기있는 라이브러리가 'sytled-components'이다.

CSS in JS의 등장

  • 모든 기술은 문제를 해결하기 위해 등장했다. 'styled-components' 또한 이전 기술의 문제점을 보완하기 위해 등장했다.
  • pure CSS의 문제점을 보완하기 위해 CSS preprocessor(전처리기)로 SASS, Scss가 등장했지만 여전히 문제점이 있다.
    -CSS 클래스명을 붙이기 어렵다.
    -정해진 가이드가 없으면 구조가 복잡해진다.
    -방대한 스타일 정보로 인한 스크롤 지옥
    -CSS 클래스로 조건부 스타일링의 한계
    -동적인 변화를 표현하기에 한계
  • css-in-js는 2018년 이후 폭발적으로 성장해왔고, styled-components는 npm 다운로드 수 기준으로 가장 인기있는 css-in-js 라이브러리다.

CSS-in-JS의 장점

  • 클래스명을 해시값으로 자동 생성하고, 클래스명 오염을 방지한다.
  • JavaScript에서 CSS 문법을 온전하게 사용할 수 있다.
  • JavaScript의 동적인 값들을 온전하게 사용할 수 있다.
  • 컴포넌트 단위로 추상화하여 적용하기 알맞다.
    => 컴포넌트와 스타일이 하나의 파일로 결합되어 모듈화가 수월해진다.

styled-components

  • 설치
    npm install --save styled-components
  • styled-components는 '고유한 클래스 명을 자동으로 생성'해 서로 다른 스타일이 전역에서 중복 적용될 우려를 줄여주고,
  • 렌더링 되는 컴포넌트에 맞는 스타일 컴포넌트를 자동으로 내보내주는 등 컴포넌트의 스타일 작성과 관리를 효율적으로 할 수 있다는 장점이 있다.

시작하기

  • styled-components 라이브러리에서 import 해온 styled 객체를 이용한다.
  • html 태그 이름 뒤 Tagged Template 문법을 활용해 CSS 속성을 정의한다. (Template Literals(``)의 확장)
import styled from 'styled-components';

render(
  <Wrapper>
  	<Title>
  	 Hello World!
        </Title>
  </Wrapper>
);

const Wrapper = styled.section`
 padding: 4em;
 background: papayawhip;
`;

const Title = styled.h1`
 font-size: 1.5em;
 text-align: center;
 color: blue;
`;

styled-components 사용하기

Adapting based on props

import styled from 'styled-components';

render(
  <div>
   <Button>Normal</Button>
   <Button width="100">Primary</Button>
  </div>
);

const Button = styled.button`
 background: ${props => props.width < 200 ? "blue" : "white"};
 color : ${props => props.primary ? "white" : "blue"};
`;
  • props를 기반으로 삼항 연산자를 붙여 스타일의 변화를 줄 수 있다.

Extending Styles

import styled from 'styled-components';

render(
  <div>
   <Button>Normal</Button>
   <TomatoAnchorButton>Tomato Button</TomatoAnchorButton>
  </div>
);

const Button = styled.div`
 color: blue;
 font-size: 14px;
 margin: 5px;
 padding: 16px 0;
 border: 2px solid blue;
`;

const TomatoAnchorButton = styled(Button.withComponent("a"))`
 color: tomato;
 border-color: tomato;
`;
  • 중복 요소가 없는 일반적인 Button 속성을 정의하고, 이 속성을 바탕으로 확장된 속성(TomatoAnchorButton)을 정해준다.
  • 이때 중복되는 속성은 새로운 속성으로 덮어진다.

Nesting

import styled from 'styled-components';

render(
  <>
   <Thing>Hello world!</Thing>
   <Thing>How ya doing?</Thing>
   <Thing className = "something">
   	<span className="contents">The sun is shining</span>
   </Thing>
   <div>Pretty nice day today.</div>
   <Thing>Don't you think?</Thing>
   <div className="something-else">
    <Thing>Splendid</Thing> 
  </div>
  </>
);

const Thing = styled.div`
 color: blue;
 
 &:hover {
  color: red;
}

&.something 

.something-else & {
  border: 1px solid;
}
`;

Global Style & ThemeProvider

  • 전역 스타일을 적용할 때 쓴다.
  • reset 설치, createGlobalStyle 에 전역 스타일을 넣고, ThemeProvider를 통해 자주 사용하는 폰트, 색상 등을 지정해 원하는 곳에 가져다 쓸 수 있다.
  • styled-reset 설치 npm install --save styled-components styled-reset
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

const GlobalStyle = createGlobalStyle`
  ${reset}
	
	// 전역스타일
	
`;

export default GlobalStyle;
  • index.js에 import 해준다.
import React from "react";
import ReactDOM from "react-dom";
import GlobalStyle from './styles/GlobalStyle';
import { ThemeProvider } from "styled-components";
import Routes from "./Routes";
import theme from "./styles/theme";

ReactDOM.render(
	<>
    <GlobalStyle />
    <ThemeProvider theme={theme}>
      <Routes />
    </ThemeProvider>
	</>,
  document.getElementById("root")
);
// theme.js

const theme = {
  background: "#FFFEFC",
  white: "#FFFFFF",
  vermilion: "#ff7425",
  orange: "#FF9900",
  opacityOrange: "rgba(242,153,74,0.5)",
  yellow: "#FFD66C",
  grey: "rgba(196,196,196,0.3)",
  middleGrey: "rgba(65,65,65,0.4)",
  deepGrey: "#828282",
  lightOrange: "rgba(255,195,170,0.3)",
  fontColor: "#2D2B2B",
  fontTitle: "'Alata', sans-serif;",
  fontContent: "'Noto Sans KR', sans-serif;",
};

export default theme;
// theme 사용

const Container = styled.div`
  background-color: ${props => props.theme.background}
`;

Mixin

  • CSS를 import해서 속성을 정의하고 원하는 요소에 쓸 수 있다.
import { css } from "styled-components"

const Navigation = styled.nav`
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  ${Sticky}
`;

const Sticky = css`
  position: fixed !important;
  background-color: white;
  border-bottom: 1px solid rgba(0, 0, 0, 0.11);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.11);
  transition: all 0.6s ease-in-out;
  color: black;
`;

//

const RingVariant = (radius, stroke = "10") => css`
  position: absolute;
  border-radius: 50%;
  height: ${radius * 2}px;
  width: ${radius * 2}px;
  border: ${stroke}px solid rgba(0, 0, 0, 0.5);
`;

Attaching additional props

render(
  <div>
    <Input placeholder="A small text input" />
    <br />
    <Input placeholder="A bigger text input" size="2em" />
  </div>
);

//attr()의 매개변수에 객체로 속성 부여
const Input = styled.input.attrs(props => ({
  // we can define static props
  type: "password",

  // or we can define dynamic ones
  size: props.size || "1em",
}))`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;

  /* here we use the dynamically computed prop */
  margin: ${props => props.size};
  padding: ${props => props.size};
`;

Animation

  • 애니메이션 및 스타일 효과를 줄 때는 keyframes를 사용한다.
// Create the keyframes
const rotate = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;

// Here we create a component that will rotate everything we pass in over two seconds
const Rotate = styled.div`
  display: inline-block;
  animation: ${rotate} 2s linear infinite;
  padding: 2rem 1rem;
  font-size: 1.2rem;
`;
render(
  <Rotate>&lt; 💅🏾 &gt;</Rotate>
);

좋은 웹페이지 즐겨찾기