IT/React

CSS-in-JS 알아보기 (Feat. styled-components)

라임웨일 2021. 4. 26. 10:07
반응형

 

 

컴포넌트 기반 프론트엔드 개발 방법이 발전하면서 CSS 개발 방법도 새로운 방법론과 생겨나고 있습니다. 웹이 점점 복잡해지고 CSS를 보다 전문적이고 체계적으로 관리하고 싶은 욕구는 2014년 페이스북 개발자인 개발자인 Christopher Chedeau aka Vjeux 의 발표에서 CSS-in-JS를 세상에 공개했고 이는 CSS 코드 작성의 새로운 대안으로 떠올랐습니다.

이 발표에서 Vjeux는 다음의 항목을 들어 CSS를 작성하는 어려움을 설명하였습니다.

 

  • Global namespace: 모든 스타일이 global에 선언되어 별도의 class 명명 규칙을 적용해야 하는 문제(클래스 이름 중복 문제)
  • Dependencies: css간의 의존관계를 관리하기 힘든 문제(스타일 상속에 의한 중복 문제)
  • Dead Code Elimination: 기능 추가, 변경, 삭제 과정에서 불필요한 CSS를 제거하기 어려운 문제(미사용 코드 처리 문제)
  • Minification: 클래스 이름의 최소화 문제
  • Sharing Constants: JS의 상태 값을 공유할 수 없는 문제(JS 코드와 값을 연동)
  • Non-deterministic Resolution: CSS 로드 순서에 따라 스타일 우선순위가 달라지는 문제(CSS 로드 순서에 따른 캐스캐이딩 스타일 변화 문제)
  • Isolation: CSS와 JS가 분리된 탓에 상속에 따른 격리가 어려운 문제

 

CSS를 조금 이해하고 있다면 모두가 공감할 수 있는 이야기들이고 그것을 해결할 뾰족한 해결책이 힘든 이슈들입니다. Facebook은 이런 문제들의 해결책으로 컴포넌트 기반 자바스크립트 인라인 스타일을 선택했다고 합니다. 여기서 CSS-in-JS 라는 명칭은 방법론이며, 실제로 작성하기 위해서는 라이브러리를 사용하는 것이 수월합니다. 

 

CSS-in-JS 라이브러리 중 가장 대표적인 'styled-components'의 다운로드를 보면 지속적으로 증가하고 있는 것을 알 수 있습니다. 

 

CSS-in-JS : styled-components (NPM trends)

 

그럼 이 styled-components에 대해 한번 알아볼게요.

 

우선 styled-components를 사용하려면 ` 기호에 대해서도 잠시 알아봐야 합니다. 우리가 스크립트에서 일반적으로 사용하는 ' 작은 따움표(Single quotaion)와는 다른 기호입니다. 

이름이 뭐예요?

`의 명칭을 알아보면 grave accent입니다. backtick, backquoto 등의 이름으로도 불리고 한국어로는 억음부호 라고 합니다. 

키보드에서 위치는 키보드마다 위치가 다를 수 있지만 일반적으로 숫자키패트 1번 키 왼쪽, Tab키 위에 있는 키입니다. 

 

우리가 styled-components를 알아보기 전에 grave accent를 먼저 살펴본 이유가 있습니다. styled-components 문법에서 grave accent를 사용하기 때문인데요. 이제 정말 styled-components 문법을 살펴볼게요.

 

저는 기본적으로 React에서 사용하는 방법을 예시로 설명드리겠습니다. 

npm을 통해 라이브러리를 설치합니다.

npm i styled-components

 

사용할 컴포넌트에서 styled라는 네이밍으로 import 후 사용할 수 있습니다.

import styled from 'styled-components'

 

우선 변수에 자신이 사용할 이름을 선언하고 스타일을 정의하면 되는데 이 때 스타일은 grave accent로 감싸줍니다.

const 컴포넌트 명 = styled.속성 태그(div, span, button....등)`
  속성 정의
`;
// Styled Components
const Button = styled.button`    
  display: inline-block;
  position: relative;
  font-size: 14px;     
  box-sizing: border-box;  
  background-color: #fff;
  color: #222;
  cursor: pointer;
`

미리 정의해놓은 컴포넌트 명을 화면에 호출해주면 선언해둔 CSS가 적용됩니다. 

해당 CSS는 컴포넌트 안에서만 동작하며 해시태그로 CSS 이름이 변환되기 때문에 다른 CSS와 충돌이 나거나 이름이 겹치는 일이 발생하지 않습니다. 

function App() {
  return (
    <div>
      안녕하세요
      <Button>OK</Button>
    </div>
  );
}

실제 변경 코드 

<div id="root">
  <div>
    안녕하세요    
    <button class="sc-htpNat fweqGX">
      OK
    </button>
  </div>
</div>

 

Extend (상속)

기존에 만들었던 컴포넌트(예제는 버튼)를 상속받아 사용할 수 있습니다.

// Styled Components
const Button = styled.button`    
  display: inline-block;
  position: relative;
  font-size: 14px;     
  box-sizing: border-box;  
  background-color: #fff;
  color: #222;
  cursor: pointer;
`

const RedButton = styled(Button)`
  background-color: red 
`;

function App() {
  return (
    <div>      
      <Button>기본 버튼</Button>
      <RedButton>스타일 상속 버튼</RedButton>
    </div>
  );
}

 

Compose (조립)

// Styled Components
const WhiteFont = css`
  color: white;
`;

const Button = styled.button`    
  display: inline-block;
  position: relative;
  font-size: 14px;     
  box-sizing: border-box;  
  background-color: #fff;
  color: #222;
  cursor: pointer;
`

const RedButton = styled(Button)`
  background-color: red
  ${WhiteFont}
`;

Props

생성된 컴포넌트에서 props 속성을 이용하여 조건절, 이벤트등 특정 스타일을 선택적으로 적용도 가능합니다.

// Styled Components
const WhiteFont = css`
  color: white;
`;

const Button = styled.button`    
  display: inline-block;
  position: relative;
  font-size: 14px;     
  box-sizing: border-box;  
  background-color: #fff;
  color: #222;
  cursor: pointer;
  
  ${(props) => (props.clicked ? WhiteFont : '')}
`
function App() { 
  const [clicked, setClicked] = useState(false); 
  const onClick = () => { setClicked(!clicked); }; 
  
  return ( 
    <div>
      <Button onClick={onClick}>click</Button>
    </div>
  );
}

Global (전역)

컴포넌트 안에서만 동작하는 CSS가 아닌 전체 페이지(Global)에 적용도 가능합니다.

const 컴포넌트명 = createGlobalStyle
const GlobalStyle = createGlobalStyle` 
  div {
    box-sizing: border-box; 
    font-size: 14px;
  } 
`;
ReactDOM.render( 
  <React.StrictMode> 
    <GlobalStyle /> 
    <App /> 
  </React.StrictMode>, 
  document.getElementById('root') 
);

보다 많은 Styled-componets의 기능을 확인 하고 싶으면 공식 홈페이지에서 참고하여 프로젝트에 적용하면 좋을 것 같습니다. 

 

감사합니다.

반응형